####

Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie, and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-youth-school-shootings-dashboard-case-study. Fifty Years of School Shootings in the United States (Version v1.0.0).

Motivation


This case study is motivated by this article:

Flannery, D. J., Modzeleski, W. & Kretschmar, J. M. Violence and School Shootings. Curr Psychiatry Rep 15, 331 (2013). DOI: 10.1007/s11920-012-0331-6

This article explores characteristics of school shootings and violence in schools and discusses why these events may occur, as well as their impact on the communities in which they occur.

This article states that the shooters of most commonly white males, but that many previous studies of shooter characterisitcs could not identify any particular “profile” of shooters.

“To date, studies of school shootings have concluded that no consistent and reliable profile of school shooters exist, and most researchers and clinicians would agree that predicting violent behavior is a slippery slope that will usually result in more false positives than false negatives.”

However previous studies note some commonalites such as:

“…most shooters were depressed, had experienced some significant loss, felt persecuted or bullied by others, and had prior difficulty coping or had previously tried suicide. Most of the shooters did not, however, have a history of drug abuse or violence or cruelty to animals, common psychiatric indicators of risk, nor did they report excessive exposure to violence in the media (though many produced their own violent themes in writings or drawings).”

Photo by Joshua Hoehne on Unsplash

“School shootings are not all the same and may require different approaches to prevention and treatment, especially with respect to identifying risk factors at the individual, school or community levels, and particularly with regard to examining the role that mental health issues may play to increase risk for perpetration. The field needs to know more about shooting incidents that are averted, those that result in injury but not death and about the characteristics of the more common occurrence of single homicide school shootings.”

Photo by Andre Hunter on Unsplash

They also point out that:

“Most media attention is on the mental health of school shooters, but we cannot forget the impact of school shooting incidents on the surviving victims, including those who may not have been injured but who may have witnessed the incident or been affected by it in other ways. Psychiatrists must pay attention to the long-term mental health consequences of these incidents on all affected parties (not just formal PTSD diagnoses, but related trauma symptoms) as well as maladaptive coping strategies that some may employ in response to such unpredictable, tragic events.”

Given this need for more research to better understand why these events occur and how they could be averted, in this case study we will demonstrate how to create a resource for others to more easily and interactively access data about school shootings. To do so we will create what is called a dashboard, which is a website that displays a report for a database. Dashboards summarize the data in a database and typically allow for users to interact with the data in some way.

Main Questions


Our main questions:

  1. What has been the yearly rate of school shootings and where have they occurred in the last 50 years (from January 1970 to June 2020)?

  2. What are the characteristics of these events?

Learning Objectives


In this case study, we will demonstrate how to create a dashboard, which is a website that displays a report about a database. We will especially focus on using packages and functions from the Tidyverse, such as package_name, package_name. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R more legible and intuitive.

The skills, methods, and concepts that students will be familiar with by the end of this case study are:

Avocado update here and in readme!

Data science skills:

  1. Importing text from a google sheets document???
  2. Apply action verbs in dplyr for data wrangling
  3. How to reshape data by pivoting between “long” and “wide” formats and separating columns into additional columns (tidyr)
  4. How to fill in data based on previous values (tidyr)
  5. How to create data visualizations with ggplot2 that are in a similar style to an existing image
  6. How to add images to plots using cowplot
  7. How to create effective bar plots to for multiple comparisons, including adding gaps between bars in bar plots, adding figure legends to the plot area, and adding comparison lines (ggplot2)

Statistical concepts and methods:


We will begin by loading the packages that we will need:

Packages used in this case study:

Package Use in this case study
here to easily load and save data
readr to import the data
dplyr to filter, subset, join, add rows to, and modify the data
stringr to manipulate character strings within the data
magrittr to pipe sequential commands
ggmap to geocode the data (which means get the latitude and longitude values for the schools)
waffle to make waffle proportion plot
flexdashboard to create the elements of the dashboard

tidyr | to change the shape or format of tibbles to wide and long, to drop rows with NA values, to separate a column into additional columns, and to fill out values based on previous values
shiny | to avocado
leaflet | to implement the create the map for our dashboard
sf | to Geocode the data avocado rmapshapper | avocado htmltools | to avocado
lubridate | to work with the data-time data
DT | to create the interactive table
ggplot2 | to create plots
directlabels | to add labels directly to lines in plots
cowplot | to add images to plots forcats | to reorder factor for plot

patchwork | to combine plots

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context


Although school shooting events that result in homicide are rare, they can have a lasting impact on the communities in which they occur. Furthermore, suicide events and shootings with no victims can also be impactful.

According to the Center for Injury Research and Prevention at the Children’s Hospital of Philadelphia:

The most common shootings on school grounds rarely involve large numbers of victims, but even a shooting of just one student at school has ramifications far beyond those directly involved. Students and staff that witness school shootings are likely to suffer from traumatic stress symptoms, become anxious or depressed and have general concerns about their safety. While many witnesses will have temporary symptoms, others will be symptomatic for a much longer period of time and even develop chronic psychiatric disorders. Even short-term impairments can cause severe distress and have profound effects on academic achievement and the social and emotional growth of impacted students.

Furthermore, fatal shootings can have vast and lasting impacts because many students can witness a single event.

Another recently published article indicates that:

Over 240,000 American students experienced a school shooting in the last two decades.

[source]

This study followed students who experienced a school shootting the United States between 2008 and 2013 and assessed their mental well-being. They found that:

Fatal school shootings have large and persistent impacts on the mental health of local youth. In the two years following a fatal school shooting, the monthly number of antidepressant prescriptions written to individuals under age 20 is 21.3 percent higher in the shooting-exposed relative to the reference areas.

Photo by Fernando @cferdo on Unsplash

Rossin-Slater, M., Schnell, M., Schwandt, H., Trejo, S. & Uniat, L. Local Exposure to School Shootings and Youth Antidepressant Use. w26563 http://www.nber.org/papers/w26563.pdf (2019) doi:10.3386/w26563.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

  1. This analysis is exploratory and, as such, does not intend to provide inferential conlcusions.

  2. This dashboard only uses one source of data. There may be school shooting events that are not listed in this data or errors in this data.

According to the database website:

“This database was developed from open-source information and may include reporting errors.”

Furthermore, according to this article schools are not required to report school shootings unless they resulted in a suicide or homicide, therefore there may be more events that result in only injury or no injuries or death that may not be included.

There are indeed events in the dataset that include zero deaths and zero injuries, but it is very likely that many of these events are not listed.

Avocado… this source from 2013 says that schools are not required to report.. is this still true?

What are the data?


We will use data from the open-source K-12 ShoolShooting Database downloaded from the Center for Homeland Defense and Security at the at the Naval Postgraduate School(NPS) in Monterey, California. This data is updated daily.

Riedman, David, and Desmond O’Neill. “CHDS – K-12 School Shooting Database.” Center for Homeland Defense and Security, June 2020, www.chds.us/ssdb.

This database includes information about school shooting events in the United States dating back to 1970. The database has additional information not shown on our dashboard including but not limited to:

  • Location of the event at the school
  • If the event occured during a sporting event
  • Time of day of the event
  • Day of the week of the event
  • source for the shooting information
  • If the event was pre-planned or not
  • Shooter’s actions immediately following the shooting
  • Shooter characteristics (affiliation with the school, if they had accomplices, if they took hostages, and their age and race)
  • victom characteristics(afficliation with the school, if they were targeted, their age and race)

According to the data base website:

The School Shooting Database Project is conducted as part of the Advanced Thinking in Homeland Security (HSx) program at the Naval Postgraduate School’s [Center for Homeland Defense and Security (CHDS)](Center for Homeland Defense and Security (CHDS).

The database compiles information from more than 25 different sources including peer-reviewed studies, government reports, mainstream media, non-profits, private websites, blogs, and crowd-sourced lists that have been analyzed, filtered, deconflicted, and cross-referenced. All of the information is based on open-source information and 3rd party reporting.

Data Import


To import the raw data file we will use the read_csv() function of the readr package.

We will use the here() function of the here package to easily locate the data within the raw_data directory within the directory that contains the .Rproj file.

We want to skip the first row that states: Updated 6/2/2020 - View graphs and research methodology on www.chds.us/ssdb If you have information about other incidents, please email ."

To do this, we can use the skip argument of this function and specify that we wish to only skip 1 row with skip = 1. We can also specify that the next row should be used for column names using the col_names = TRUE argument.

We can use the glimpse function of the dplyr package to take a look at columns within the database:

Rows: 1,556
Columns: 47
$ Date                                                                                                                                                 <chr> …
$ School                                                                                                                                               <chr> …
$ City                                                                                                                                                 <chr> …
$ State                                                                                                                                                <chr> …
$ `Reliability Score (1-5)`                                                                                                                            <dbl> …
$ `Killed (includes shooter)`                                                                                                                          <dbl> …
$ Wounded                                                                                                                                              <dbl> …
$ `Total Injured/Killed Victims`                                                                                                                       <dbl> …
$ `Gender of Victims (M/F/Both)`                                                                                                                       <chr> …
$ `Victim's Affiliation w/ School`                                                                                                                     <chr> …
$ `Victim's age(s)`                                                                                                                                    <dbl> …
$ `Victims Race`                                                                                                                                       <chr> …
$ `Victim Ethnicity`                                                                                                                                   <chr> …
$ `Targeted Specific Victim(s)`                                                                                                                        <chr> …
$ `Random Victims`                                                                                                                                     <chr> …
$ `Bullied (Y/N/ N/A)`                                                                                                                                 <chr> …
$ `Domestic Violence (Y/N)`                                                                                                                            <chr> …
$ `Suicide (Shooter was only victim) Y/N/ N/A`                                                                                                         <chr> …
$ `Suicide (shot self immediately following initial shootings) Y/N/ N/A`                                                                               <chr> …
$ `Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A` <chr> …
$ `Suicide (or attempted suicide) by Shooter (Y/N)`                                                                                                    <chr> …
$ `Shooter's actions immediately after shots fired`                                                                                                    <chr> …
$ `Pre-planned school attack`                                                                                                                          <chr> …
$ Summary                                                                                                                                              <chr> …
$ Category                                                                                                                                             <chr> …
$ `School Type`                                                                                                                                        <chr> …
$ `Narrative (Detailed Summary/ Background)`                                                                                                           <chr> …
$ Sources                                                                                                                                              <chr> …
$ `Time of Occurrence (12 hour AM/PM)`                                                                                                                 <time> …
$ `Duration (minutes)`                                                                                                                                 <dbl> …
$ `Day of week (formula)`                                                                                                                              <chr> …
$ `During School Day (Y/N)`                                                                                                                            <chr> …
$ `Time Period`                                                                                                                                        <chr> …
$ `During a Sporting Event (Y/N)`                                                                                                                      <chr> …
$ `During a school sponsored event (school dance, concert, play, activity)`                                                                            <chr> …
$ Location                                                                                                                                             <chr> …
$ `Number of Shots Fired`                                                                                                                              <dbl> …
$ `Firearm Type`                                                                                                                                       <chr> …
$ `Number of Shooters`                                                                                                                                 <dbl> …
$ `Shooter Name`                                                                                                                                       <chr> …
$ `Shooter Age`                                                                                                                                        <dbl> …
$ `Shooter Gender`                                                                                                                                     <chr> …
$ Race                                                                                                                                                 <chr> …
$ `Shooter Ethnicity`                                                                                                                                  <chr> …
$ `Shooter's Affiliation with School`                                                                                                                  <chr> …
$ `Shooter had an accomplice who did not fire gun (Y/N)`                                                                                               <chr> …
$ `Hostages Taken (Y/N)`                                                                                                                               <chr> …

We can also use the utils str() function to see more detials about the values. Typically we would be able to see these with glimpse() but some of the columns have very long names, thus obscuring the first few values in the output.

tibble [1,556 × 47] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Date                                                                                                                                              : chr [1:1556] "1/5/1970" "1/5/1970" "1/5/1970" "2/6/1970" ...
 $ School                                                                                                                                            : chr [1:1556] "Hine Junior High School" "Sousa Junior High" "Unnamed High School" "John F. Kennedy High School" ...
 $ City                                                                                                                                              : chr [1:1556] "Washington" "Washington" "Washington" "Cleveland" ...
 $ State                                                                                                                                             : chr [1:1556] "DC" "DC" "DC" "OH" ...
 $ Reliability Score (1-5)                                                                                                                           : num [1:1556] 3 3 2 2 2 3 3 2 2 2 ...
 $ Killed (includes shooter)                                                                                                                         : num [1:1556] 1 0 0 0 0 1 1 0 0 0 ...
 $ Wounded                                                                                                                                           : num [1:1556] 0 1 0 1 2 5 0 1 2 1 ...
 $ Total Injured/Killed Victims                                                                                                                      : num [1:1556] 1 1 0 1 2 6 1 1 2 1 ...
 $ Gender of Victims (M/F/Both)                                                                                                                      : chr [1:1556] "Male" "Male" "No Victims" "Male" ...
 $ Victim's Affiliation w/ School                                                                                                                    : chr [1:1556] "Student" "Student" "No Victims" "Student" ...
 $ Victim's age(s)                                                                                                                                   : num [1:1556] 15 NA NA 18 NA NA 18 19 NA 15 ...
 $ Victims Race                                                                                                                                      : chr [1:1556] NA NA "No Victims" NA ...
 $ Victim Ethnicity                                                                                                                                  : chr [1:1556] NA NA "No Victims" NA ...
 $ Targeted Specific Victim(s)                                                                                                                       : chr [1:1556] "No" "No" "Yes" "Yes" ...
 $ Random Victims                                                                                                                                    : chr [1:1556] "Yes" "Yes" "No" "No" ...
 $ Bullied (Y/N/ N/A)                                                                                                                                : chr [1:1556] "No" "No" "No" "No" ...
 $ Domestic Violence (Y/N)                                                                                                                           : chr [1:1556] "No" "No" "No" "No" ...
 $ Suicide (Shooter was only victim) Y/N/ N/A                                                                                                        : chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (shot self immediately following initial shootings) Y/N/ N/A                                                                              : chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A: chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (or attempted suicide) by Shooter (Y/N)                                                                                                   : chr [1:1556] "No" "No" "No" "No" ...
 $ Shooter's actions immediately after shots fired                                                                                                   : chr [1:1556] "Unknown if Subdued Surrendered or Fled" "Immediately Surrendered" "Fled" "Unknown if Subdued Surrendered or Fled" ...
 $ Pre-planned school attack                                                                                                                         : chr [1:1556] "No" "No" "No" "No" ...
 $ Summary                                                                                                                                           : chr [1:1556] "Didn't know how to operate pistol, cocked hammer and couldn't get it to safely release causing accidental discharge" "Occurred during horseplay in the school" "Student shot at twice during attempted robbery on playground" "Argument in school hallway escalated into shooting" ...
 $ Category                                                                                                                                          : chr [1:1556] "Accidental" "Accidental" "Robbery" "Escalation of Dispute" ...
 $ School Type                                                                                                                                       : chr [1:1556] "High" "Junior High" "High" "High" ...
 $ Narrative (Detailed Summary/ Background)                                                                                                          : chr [1:1556] "Student showing off gun cocked hammer and could not get it to release causing accidental discharge and killing "| __truncated__ "14YOM student shot during \"horseplay\" in the school hallway. Friend of the victim surrendered to police." "Group of 10 teens attempted to rob 16YOM (James Owens) on school playground. When victim ran, unknown teen susp"| __truncated__ "Argument between shooter and victim escalated into shooting in school hallway." ...
 $ Sources                                                                                                                                           : chr [1:1556] "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998" "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998 https://www.newspapers.com/image/156467116/?"| __truncated__ "https://www.newspapers.com/image/156467116/?terms=school%2Bshooting" "https://www.newspapers.com/image/18059538/?terms=school%2Bshooting" ...
 $ Time of Occurrence (12 hour AM/PM)                                                                                                                : 'hms' num [1:1556] NA NA NA NA ...
  ..- attr(*, "units")= chr "secs"
 $ Duration (minutes)                                                                                                                                : num [1:1556] 1 1 1 1 NA 8 1 1 NA 1 ...
 $ Day of week (formula)                                                                                                                             : chr [1:1556] "Mon" "Mon" "Mon" "Fri" ...
 $ During School Day (Y/N)                                                                                                                           : chr [1:1556] "Yes" "Yes" "Yes" "Yes" ...
 $ Time Period                                                                                                                                       : chr [1:1556] NA NA NA NA ...
 $ During a Sporting Event (Y/N)                                                                                                                     : chr [1:1556] "No" "No" "No" "No" ...
 $ During a school sponsored event (school dance, concert, play, activity)                                                                           : chr [1:1556] "No" "No" "No" "No" ...
 $ Location                                                                                                                                          : chr [1:1556] "Inside School Building" "Inside School Building" "Outside on School Property" "Inside School Building" ...
 $ Number of Shots Fired                                                                                                                             : num [1:1556] 1 1 2 4 NA NA 1 1 2 NA ...
 $ Firearm Type                                                                                                                                      : chr [1:1556] "Handgun" "Handgun" "Handgun" "Handgun" ...
 $ Number of Shooters                                                                                                                                : num [1:1556] 1 1 1 1 2 8 1 1 1 2 ...
 $ Shooter Name                                                                                                                                      : chr [1:1556] "Minor" "Minor" "Unknown" "Gertis J. Perry" ...
 $ Shooter Age                                                                                                                                       : num [1:1556] 15 NA NA 18 NA NA 16 18 15 NA ...
 $ Shooter Gender                                                                                                                                    : chr [1:1556] "Male" "Male" "Male" "Male" ...
 $ Race                                                                                                                                              : chr [1:1556] NA NA NA NA ...
 $ Shooter Ethnicity                                                                                                                                 : chr [1:1556] NA NA NA "Not Hispanic or Latino" ...
 $ Shooter's Affiliation with School                                                                                                                 : chr [1:1556] "Student" "Student" "Student" "Student" ...
 $ Shooter had an accomplice who did not fire gun (Y/N)                                                                                              : chr [1:1556] "Yes" "No" "Yes" "No" ...
 $ Hostages Taken (Y/N)                                                                                                                              : chr [1:1556] "No" "No" "No" "No" ...
 - attr(*, "spec")=
  .. cols(
  ..   Date = col_character(),
  ..   School = col_character(),
  ..   City = col_character(),
  ..   State = col_character(),
  ..   `Reliability Score (1-5)` = col_double(),
  ..   `Killed (includes shooter)` = col_double(),
  ..   Wounded = col_double(),
  ..   `Total Injured/Killed Victims` = col_double(),
  ..   `Gender of Victims (M/F/Both)` = col_character(),
  ..   `Victim's Affiliation w/ School` = col_character(),
  ..   `Victim's age(s)` = col_double(),
  ..   `Victims Race` = col_character(),
  ..   `Victim Ethnicity` = col_character(),
  ..   `Targeted Specific Victim(s)` = col_character(),
  ..   `Random Victims` = col_character(),
  ..   `Bullied (Y/N/ N/A)` = col_character(),
  ..   `Domestic Violence (Y/N)` = col_character(),
  ..   `Suicide (Shooter was only victim) Y/N/ N/A` = col_character(),
  ..   `Suicide (shot self immediately following initial shootings) Y/N/ N/A` = col_character(),
  ..   `Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A` = col_character(),
  ..   `Suicide (or attempted suicide) by Shooter (Y/N)` = col_character(),
  ..   `Shooter's actions immediately after shots fired` = col_character(),
  ..   `Pre-planned school attack` = col_character(),
  ..   Summary = col_character(),
  ..   Category = col_character(),
  ..   `School Type` = col_character(),
  ..   `Narrative (Detailed Summary/ Background)` = col_character(),
  ..   Sources = col_character(),
  ..   `Time of Occurrence (12 hour AM/PM)` = col_time(format = ""),
  ..   `Duration (minutes)` = col_double(),
  ..   `Day of week (formula)` = col_character(),
  ..   `During School Day (Y/N)` = col_character(),
  ..   `Time Period` = col_character(),
  ..   `During a Sporting Event (Y/N)` = col_character(),
  ..   `During a school sponsored event (school dance, concert, play, activity)` = col_character(),
  ..   Location = col_character(),
  ..   `Number of Shots Fired` = col_double(),
  ..   `Firearm Type` = col_character(),
  ..   `Number of Shooters` = col_double(),
  ..   `Shooter Name` = col_character(),
  ..   `Shooter Age` = col_double(),
  ..   `Shooter Gender` = col_character(),
  ..   Race = col_character(),
  ..   `Shooter Ethnicity` = col_character(),
  ..   `Shooter's Affiliation with School` = col_character(),
  ..   `Shooter had an accomplice who did not fire gun (Y/N)` = col_character(),
  ..   `Hostages Taken (Y/N)` = col_character()
  .. )

Data Exploration and Wrangling


Luckily, our data is already in pretty good shape, but we want to make our data more useful for our dashboard.

Adding state name

It would be useful to have the full state name in our data, rather than just the abbreviation.

We can do so by using data related to the US 50 states in a dataset called state that is automatically loaded with R sessions in the datasets package. The state.abb object is a list of the state abbreviations and state.name is a list of the state names.

 [1] "AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA" "HI" "ID" "IL" "IN" "IA"
[16] "KS" "KY" "LA" "ME" "MD" "MA" "MI" "MN" "MS" "MO" "MT" "NE" "NV" "NH" "NJ"
[31] "NM" "NY" "NC" "ND" "OH" "OK" "OR" "PA" "RI" "SC" "SD" "TN" "TX" "UT" "VT"
[46] "VA" "WA" "WV" "WI" "WY"
 [1] "Alabama"        "Alaska"         "Arizona"        "Arkansas"      
 [5] "California"     "Colorado"       "Connecticut"    "Delaware"      
 [9] "Florida"        "Georgia"        "Hawaii"         "Idaho"         
[13] "Illinois"       "Indiana"        "Iowa"           "Kansas"        
[17] "Kentucky"       "Louisiana"      "Maine"          "Maryland"      
[21] "Massachusetts"  "Michigan"       "Minnesota"      "Mississippi"   
[25] "Missouri"       "Montana"        "Nebraska"       "Nevada"        
[29] "New Hampshire"  "New Jersey"     "New Mexico"     "New York"      
[33] "North Carolina" "North Dakota"   "Ohio"           "Oklahoma"      
[37] "Oregon"         "Pennsylvania"   "Rhode Island"   "South Carolina"
[41] "South Dakota"   "Tennessee"      "Texas"          "Utah"          
[45] "Vermont"        "Virginia"       "Washington"     "West Virginia" 
[49] "Wisconsin"      "Wyoming"       

We will combine these using the tibble() function of the tibble() package.

# A tibble: 4 x 2
  State_abb State   
  <chr>     <chr>   
1 AL        Alabama 
2 AK        Alaska  
3 AZ        Arizona 
4 AR        Arkansas

Now we will combine this with our data using the left_join() function of the dplyr package. avocado add explanation and join images https://dplyr.tidyverse.org/reference/join.html

# A tibble: 4 x 4
  School                      City       State_abb State
  <chr>                       <chr>      <chr>     <chr>
1 Hine Junior High School     Washington DC        <NA> 
2 Sousa Junior High           Washington DC        <NA> 
3 Unnamed High School         Washington DC        <NA> 
4 John F. Kennedy High School Cleveland  OH        Ohio 

Reformating dates

We also want to reformat our date values and create a Date_year variable based on the year in each date. We can use the lubridate package for this.

The mdy() function converts dates into a format where dates are listed as month, date, and year with hyphens in between. The year() function can then be used to extract just the year from each date.

# A tibble: 1,556 x 2
   Date       Date_year
   <date>         <dbl>
 1 1970-01-05      1970
 2 1970-01-05      1970
 3 1970-01-05      1970
 4 1970-02-06      1970
 5 1970-03-23      1970
 6 1970-04-15      1970
 7 1970-04-22      1970
 8 1970-05-08      1970
 9 1970-05-15      1970
10 1970-08-28      1970
# … with 1,546 more rows

Looks good!

One last thing to do is to convert Yes and No values into TRUE and FALSE.

First let’s take a look at our data:

tibble [1,556 × 49] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Date                                                                                                                                              : Date[1:1556], format: "1970-01-05" "1970-01-05" ...
 $ School                                                                                                                                            : chr [1:1556] "Hine Junior High School" "Sousa Junior High" "Unnamed High School" "John F. Kennedy High School" ...
 $ City                                                                                                                                              : chr [1:1556] "Washington" "Washington" "Washington" "Cleveland" ...
 $ State_abb                                                                                                                                         : chr [1:1556] "DC" "DC" "DC" "OH" ...
 $ Reliability Score (1-5)                                                                                                                           : num [1:1556] 3 3 2 2 2 3 3 2 2 2 ...
 $ Killed (includes shooter)                                                                                                                         : num [1:1556] 1 0 0 0 0 1 1 0 0 0 ...
 $ Wounded                                                                                                                                           : num [1:1556] 0 1 0 1 2 5 0 1 2 1 ...
 $ Total Injured/Killed Victims                                                                                                                      : num [1:1556] 1 1 0 1 2 6 1 1 2 1 ...
 $ Gender of Victims (M/F/Both)                                                                                                                      : chr [1:1556] "Male" "Male" "No Victims" "Male" ...
 $ Victim's Affiliation w/ School                                                                                                                    : chr [1:1556] "Student" "Student" "No Victims" "Student" ...
 $ Victim's age(s)                                                                                                                                   : num [1:1556] 15 NA NA 18 NA NA 18 19 NA 15 ...
 $ Victims Race                                                                                                                                      : chr [1:1556] NA NA "No Victims" NA ...
 $ Victim Ethnicity                                                                                                                                  : chr [1:1556] NA NA "No Victims" NA ...
 $ Targeted Specific Victim(s)                                                                                                                       : chr [1:1556] "No" "No" "Yes" "Yes" ...
 $ Random Victims                                                                                                                                    : chr [1:1556] "Yes" "Yes" "No" "No" ...
 $ Bullied (Y/N/ N/A)                                                                                                                                : chr [1:1556] "No" "No" "No" "No" ...
 $ Domestic Violence (Y/N)                                                                                                                           : chr [1:1556] "No" "No" "No" "No" ...
 $ Suicide (Shooter was only victim) Y/N/ N/A                                                                                                        : chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (shot self immediately following initial shootings) Y/N/ N/A                                                                              : chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A: chr [1:1556] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (or attempted suicide) by Shooter (Y/N)                                                                                                   : chr [1:1556] "No" "No" "No" "No" ...
 $ Shooter's actions immediately after shots fired                                                                                                   : chr [1:1556] "Unknown if Subdued Surrendered or Fled" "Immediately Surrendered" "Fled" "Unknown if Subdued Surrendered or Fled" ...
 $ Pre-planned school attack                                                                                                                         : chr [1:1556] "No" "No" "No" "No" ...
 $ Summary                                                                                                                                           : chr [1:1556] "Didn't know how to operate pistol, cocked hammer and couldn't get it to safely release causing accidental discharge" "Occurred during horseplay in the school" "Student shot at twice during attempted robbery on playground" "Argument in school hallway escalated into shooting" ...
 $ Category                                                                                                                                          : chr [1:1556] "Accidental" "Accidental" "Robbery" "Escalation of Dispute" ...
 $ School Type                                                                                                                                       : chr [1:1556] "High" "Junior High" "High" "High" ...
 $ Narrative (Detailed Summary/ Background)                                                                                                          : chr [1:1556] "Student showing off gun cocked hammer and could not get it to release causing accidental discharge and killing "| __truncated__ "14YOM student shot during \"horseplay\" in the school hallway. Friend of the victim surrendered to police." "Group of 10 teens attempted to rob 16YOM (James Owens) on school playground. When victim ran, unknown teen susp"| __truncated__ "Argument between shooter and victim escalated into shooting in school hallway." ...
 $ Sources                                                                                                                                           : chr [1:1556] "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998" "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998 https://www.newspapers.com/image/156467116/?"| __truncated__ "https://www.newspapers.com/image/156467116/?terms=school%2Bshooting" "https://www.newspapers.com/image/18059538/?terms=school%2Bshooting" ...
 $ Time of Occurrence (12 hour AM/PM)                                                                                                                : 'hms' num [1:1556] NA NA NA NA ...
  ..- attr(*, "units")= chr "secs"
 $ Duration (minutes)                                                                                                                                : num [1:1556] 1 1 1 1 NA 8 1 1 NA 1 ...
 $ Day of week (formula)                                                                                                                             : chr [1:1556] "Mon" "Mon" "Mon" "Fri" ...
 $ During School Day (Y/N)                                                                                                                           : chr [1:1556] "Yes" "Yes" "Yes" "Yes" ...
 $ Time Period                                                                                                                                       : chr [1:1556] NA NA NA NA ...
 $ During a Sporting Event (Y/N)                                                                                                                     : chr [1:1556] "No" "No" "No" "No" ...
 $ During a school sponsored event (school dance, concert, play, activity)                                                                           : chr [1:1556] "No" "No" "No" "No" ...
 $ Location                                                                                                                                          : chr [1:1556] "Inside School Building" "Inside School Building" "Outside on School Property" "Inside School Building" ...
 $ Number of Shots Fired                                                                                                                             : num [1:1556] 1 1 2 4 NA NA 1 1 2 NA ...
 $ Firearm Type                                                                                                                                      : chr [1:1556] "Handgun" "Handgun" "Handgun" "Handgun" ...
 $ Number of Shooters                                                                                                                                : num [1:1556] 1 1 1 1 2 8 1 1 1 2 ...
 $ Shooter Name                                                                                                                                      : chr [1:1556] "Minor" "Minor" "Unknown" "Gertis J. Perry" ...
 $ Shooter Age                                                                                                                                       : num [1:1556] 15 NA NA 18 NA NA 16 18 15 NA ...
 $ Shooter Gender                                                                                                                                    : chr [1:1556] "Male" "Male" "Male" "Male" ...
 $ Race                                                                                                                                              : chr [1:1556] NA NA NA NA ...
 $ Shooter Ethnicity                                                                                                                                 : chr [1:1556] NA NA NA "Not Hispanic or Latino" ...
 $ Shooter's Affiliation with School                                                                                                                 : chr [1:1556] "Student" "Student" "Student" "Student" ...
 $ Shooter had an accomplice who did not fire gun (Y/N)                                                                                              : chr [1:1556] "Yes" "No" "Yes" "No" ...
 $ Hostages Taken (Y/N)                                                                                                                              : chr [1:1556] "No" "No" "No" "No" ...
 $ State                                                                                                                                             : chr [1:1556] NA NA NA "Ohio" ...
 $ Date_year                                                                                                                                         : num [1:1556] 1970 1970 1970 1970 1970 1970 1970 1970 1970 1970 ...
 - attr(*, "spec")=
  .. cols(
  ..   Date = col_character(),
  ..   School = col_character(),
  ..   City = col_character(),
  ..   State = col_character(),
  ..   `Reliability Score (1-5)` = col_double(),
  ..   `Killed (includes shooter)` = col_double(),
  ..   Wounded = col_double(),
  ..   `Total Injured/Killed Victims` = col_double(),
  ..   `Gender of Victims (M/F/Both)` = col_character(),
  ..   `Victim's Affiliation w/ School` = col_character(),
  ..   `Victim's age(s)` = col_double(),
  ..   `Victims Race` = col_character(),
  ..   `Victim Ethnicity` = col_character(),
  ..   `Targeted Specific Victim(s)` = col_character(),
  ..   `Random Victims` = col_character(),
  ..   `Bullied (Y/N/ N/A)` = col_character(),
  ..   `Domestic Violence (Y/N)` = col_character(),
  ..   `Suicide (Shooter was only victim) Y/N/ N/A` = col_character(),
  ..   `Suicide (shot self immediately following initial shootings) Y/N/ N/A` = col_character(),
  ..   `Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A` = col_character(),
  ..   `Suicide (or attempted suicide) by Shooter (Y/N)` = col_character(),
  ..   `Shooter's actions immediately after shots fired` = col_character(),
  ..   `Pre-planned school attack` = col_character(),
  ..   Summary = col_character(),
  ..   Category = col_character(),
  ..   `School Type` = col_character(),
  ..   `Narrative (Detailed Summary/ Background)` = col_character(),
  ..   Sources = col_character(),
  ..   `Time of Occurrence (12 hour AM/PM)` = col_time(format = ""),
  ..   `Duration (minutes)` = col_double(),
  ..   `Day of week (formula)` = col_character(),
  ..   `During School Day (Y/N)` = col_character(),
  ..   `Time Period` = col_character(),
  ..   `During a Sporting Event (Y/N)` = col_character(),
  ..   `During a school sponsored event (school dance, concert, play, activity)` = col_character(),
  ..   Location = col_character(),
  ..   `Number of Shots Fired` = col_double(),
  ..   `Firearm Type` = col_character(),
  ..   `Number of Shooters` = col_double(),
  ..   `Shooter Name` = col_character(),
  ..   `Shooter Age` = col_double(),
  ..   `Shooter Gender` = col_character(),
  ..   Race = col_character(),
  ..   `Shooter Ethnicity` = col_character(),
  ..   `Shooter's Affiliation with School` = col_character(),
  ..   `Shooter had an accomplice who did not fire gun (Y/N)` = col_character(),
  ..   `Hostages Taken (Y/N)` = col_character()
  .. )

We see that many of the varaibles have either Yes or No values or Y and N values. These are the variables that have Y/N in the name or the Targeted Specific Victim(s), Random Victims, Pre-planned school attack variables. We can make these consistently TRUE and FALSE by using the case_when() function of the dplyr package. This function allows us to specify new values for existing values, simlarly to the recode() function also of dplyr. The benefit of the case_when() function, is that changing the values to TRUE or FALSE also results in the class type of the variable changing to type logical (which is interpreted as a binary variable with TRUE and FALSE values) otherwise, with recode() the variables would remain as class type character.

click here for more details about the differences between recode() and case_when()`

avocado check on these statements - this does not seem to be true for case_when despite what the documentation says “If no cases match, NA is returned.”

Note, that with recode() there is the option that other values be recoded to NA althought this is not the default, however with case_when() other values not explicitly assigned in the case_when() statement will be NA. Further more only values can be used on the left side when using recode() whereas case_when() accepts expressions that need to be evaluated, unless using the := opperator.???


avocado add links about this/ maybe add /check if we already added the class type stuff from the other case studies - indeed casewhen in other cases seems to automatically make all other cases NA but was that the case here?

To implement the case_when() recoding of values, the exisiting values are written on the left of the ~ sign (quotation marks necessary) and new values are written on the right (quotations marks are not necessary as these are TRUE and FALSE statments). We will also use the across() function of the dplyr package and the matches() function of the tidyselect packge to allow us to apply this to all of the variables that have a pattern that that matches any of those of the variables we want to change. The | symbol is interpreted as an or, thus any variables that has a name that matches any of these patterns will be changed. fThe across() function then applies the case_when() function to all of these variables. Notice that the ~ symbol is necessary before the funtion that is applied using across().

# A tibble: 0 x 49
# … with 49 variables: Date <date>, School <chr>, City <chr>, State_abb <chr>,
#   `Reliability Score (1-5)` <dbl>, `Killed (includes shooter)` <dbl>,
#   Wounded <dbl>, `Total Injured/Killed Victims` <dbl>, `Gender of Victims
#   (M/F/Both)` <chr>, `Victim's Affiliation w/ School` <chr>, `Victim's
#   age(s)` <dbl>, `Victims Race` <chr>, `Victim Ethnicity` <chr>, `Targeted
#   Specific Victim(s)` <chr>, `Random Victims` <chr>, `Bullied (Y/N/
#   N/A)` <chr>, `Domestic Violence (Y/N)` <chr>, `Suicide (Shooter was only
#   victim) Y/N/ N/A` <chr>, `Suicide (shot self immediately following initial
#   shootings) Y/N/ N/A` <chr>, `Suicide (e.g., shot self at end of incident -
#   time period between first shots and suicide, different location, when
#   confronted by police) Y/N/ N/A` <chr>, `Suicide (or attempted suicide) by
#   Shooter (Y/N)` <chr>, `Shooter's actions immediately after shots
#   fired` <chr>, `Pre-planned school attack` <chr>, Summary <chr>,
#   Category <chr>, `School Type` <chr>, `Narrative (Detailed Summary/
#   Background)` <chr>, Sources <chr>, `Time of Occurrence (12 hour
#   AM/PM)` <time>, `Duration (minutes)` <dbl>, `Day of week (formula)` <chr>,
#   `During School Day (Y/N)` <chr>, `Time Period` <chr>, `During a Sporting
#   Event (Y/N)` <chr>, `During a school sponsored event (school dance,
#   concert, play, activity)` <chr>, Location <chr>, `Number of Shots
#   Fired` <dbl>, `Firearm Type` <chr>, `Number of Shooters` <dbl>, `Shooter
#   Name` <chr>, `Shooter Age` <dbl>, `Shooter Gender` <chr>, Race <chr>,
#   `Shooter Ethnicity` <chr>, `Shooter's Affiliation with School` <chr>,
#   `Shooter had an accomplice who did not fire gun (Y/N)` <chr>, `Hostages
#   Taken (Y/N)` <chr>, State <chr>, Date_year <dbl>
# A tibble: 1,556 x 13
   `Targeted Speci… `Random Victims` `Bullied (Y/N/ … `Domestic Viole…
   <chr>            <chr>            <chr>            <chr>           
 1 No               Yes              No               No              
 2 No               Yes              No               No              
 3 Yes              No               No               No              
 4 Yes              No               No               No              
 5 No               No               No               No              
 6 Yes              Yes              No               No              
 7 Yes              No               No               No              
 8 Yes              No               No               No              
 9 No               Yes              <NA>             No              
10 Yes              No               No               No              
# … with 1,546 more rows, and 9 more variables: `Suicide (Shooter was only
#   victim) Y/N/ N/A` <chr>, `Suicide (shot self immediately following initial
#   shootings) Y/N/ N/A` <chr>, `Suicide (e.g., shot self at end of incident -
#   time period between first shots and suicide, different location, when
#   confronted by police) Y/N/ N/A` <chr>, `Suicide (or attempted suicide) by
#   Shooter (Y/N)` <chr>, `Pre-planned school attack` <chr>, `During School Day
#   (Y/N)` <chr>, `During a Sporting Event (Y/N)` <chr>, `Shooter had an
#   accomplice who did not fire gun (Y/N)` <chr>, `Hostages Taken (Y/N)` <chr>
# A tibble: 1,556 x 13
   `Targeted Speci… `Random Victims` `Bullied (Y/N/ … `Domestic Viole…
   <lgl>            <lgl>            <lgl>            <lgl>           
 1 FALSE            TRUE             FALSE            FALSE           
 2 FALSE            TRUE             FALSE            FALSE           
 3 TRUE             FALSE            FALSE            FALSE           
 4 TRUE             FALSE            FALSE            FALSE           
 5 FALSE            FALSE            FALSE            FALSE           
 6 TRUE             TRUE             FALSE            FALSE           
 7 TRUE             FALSE            FALSE            FALSE           
 8 TRUE             FALSE            FALSE            FALSE           
 9 FALSE            TRUE             NA               FALSE           
10 TRUE             FALSE            FALSE            FALSE           
# … with 1,546 more rows, and 9 more variables: `Suicide (Shooter was only
#   victim) Y/N/ N/A` <lgl>, `Suicide (shot self immediately following initial
#   shootings) Y/N/ N/A` <lgl>, `Suicide (e.g., shot self at end of incident -
#   time period between first shots and suicide, different location, when
#   confronted by police) Y/N/ N/A` <lgl>, `Suicide (or attempted suicide) by
#   Shooter (Y/N)` <lgl>, `Pre-planned school attack` <lgl>, `During School Day
#   (Y/N)` <lgl>, `During a Sporting Event (Y/N)` <lgl>, `Shooter had an
#   accomplice who did not fire gun (Y/N)` <lgl>, `Hostages Taken (Y/N)` <lgl>
# A tibble: 0 x 49
# … with 49 variables: Date <date>, School <chr>, City <chr>, State_abb <chr>,
#   `Reliability Score (1-5)` <dbl>, `Killed (includes shooter)` <dbl>,
#   Wounded <dbl>, `Total Injured/Killed Victims` <dbl>, `Gender of Victims
#   (M/F/Both)` <chr>, `Victim's Affiliation w/ School` <chr>, `Victim's
#   age(s)` <dbl>, `Victims Race` <chr>, `Victim Ethnicity` <chr>, `Targeted
#   Specific Victim(s)` <lgl>, `Random Victims` <lgl>, `Bullied (Y/N/
#   N/A)` <lgl>, `Domestic Violence (Y/N)` <lgl>, `Suicide (Shooter was only
#   victim) Y/N/ N/A` <lgl>, `Suicide (shot self immediately following initial
#   shootings) Y/N/ N/A` <lgl>, `Suicide (e.g., shot self at end of incident -
#   time period between first shots and suicide, different location, when
#   confronted by police) Y/N/ N/A` <lgl>, `Suicide (or attempted suicide) by
#   Shooter (Y/N)` <lgl>, `Shooter's actions immediately after shots
#   fired` <chr>, `Pre-planned school attack` <lgl>, Summary <chr>,
#   Category <chr>, `School Type` <chr>, `Narrative (Detailed Summary/
#   Background)` <chr>, Sources <chr>, `Time of Occurrence (12 hour
#   AM/PM)` <time>, `Duration (minutes)` <dbl>, `Day of week (formula)` <chr>,
#   `During School Day (Y/N)` <lgl>, `Time Period` <chr>, `During a Sporting
#   Event (Y/N)` <lgl>, `During a school sponsored event (school dance,
#   concert, play, activity)` <chr>, Location <chr>, `Number of Shots
#   Fired` <dbl>, `Firearm Type` <chr>, `Number of Shooters` <dbl>, `Shooter
#   Name` <chr>, `Shooter Age` <dbl>, `Shooter Gender` <chr>, Race <chr>,
#   `Shooter Ethnicity` <chr>, `Shooter's Affiliation with School` <chr>,
#   `Shooter had an accomplice who did not fire gun (Y/N)` <lgl>, `Hostages
#   Taken (Y/N)` <lgl>, State <chr>, Date_year <dbl>

tibble [1,556 × 49] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Date                                                                                                                                              : Date[1:1556], format: "1970-01-05" "1970-01-05" ...
 $ School                                                                                                                                            : chr [1:1556] "Hine Junior High School" "Sousa Junior High" "Unnamed High School" "John F. Kennedy High School" ...
 $ City                                                                                                                                              : chr [1:1556] "Washington" "Washington" "Washington" "Cleveland" ...
 $ State_abb                                                                                                                                         : chr [1:1556] "DC" "DC" "DC" "OH" ...
 $ Reliability Score (1-5)                                                                                                                           : num [1:1556] 3 3 2 2 2 3 3 2 2 2 ...
 $ Killed (includes shooter)                                                                                                                         : num [1:1556] 1 0 0 0 0 1 1 0 0 0 ...
 $ Wounded                                                                                                                                           : num [1:1556] 0 1 0 1 2 5 0 1 2 1 ...
 $ Total Injured/Killed Victims                                                                                                                      : num [1:1556] 1 1 0 1 2 6 1 1 2 1 ...
 $ Gender of Victims (M/F/Both)                                                                                                                      : chr [1:1556] "Male" "Male" "No Victims" "Male" ...
 $ Victim's Affiliation w/ School                                                                                                                    : chr [1:1556] "Student" "Student" "No Victims" "Student" ...
 $ Victim's age(s)                                                                                                                                   : num [1:1556] 15 NA NA 18 NA NA 18 19 NA 15 ...
 $ Victims Race                                                                                                                                      : chr [1:1556] NA NA "No Victims" NA ...
 $ Victim Ethnicity                                                                                                                                  : chr [1:1556] NA NA "No Victims" NA ...
 $ Targeted Specific Victim(s)                                                                                                                       : logi [1:1556] FALSE FALSE TRUE TRUE FALSE TRUE ...
 $ Random Victims                                                                                                                                    : logi [1:1556] TRUE TRUE FALSE FALSE FALSE TRUE ...
 $ Bullied (Y/N/ N/A)                                                                                                                                : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Domestic Violence (Y/N)                                                                                                                           : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Suicide (Shooter was only victim) Y/N/ N/A                                                                                                        : logi [1:1556] NA NA NA NA NA NA ...
 $ Suicide (shot self immediately following initial shootings) Y/N/ N/A                                                                              : logi [1:1556] NA NA NA NA NA NA ...
 $ Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A: logi [1:1556] NA NA NA NA NA NA ...
 $ Suicide (or attempted suicide) by Shooter (Y/N)                                                                                                   : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Shooter's actions immediately after shots fired                                                                                                   : chr [1:1556] "Unknown if Subdued Surrendered or Fled" "Immediately Surrendered" "Fled" "Unknown if Subdued Surrendered or Fled" ...
 $ Pre-planned school attack                                                                                                                         : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Summary                                                                                                                                           : chr [1:1556] "Didn't know how to operate pistol, cocked hammer and couldn't get it to safely release causing accidental discharge" "Occurred during horseplay in the school" "Student shot at twice during attempted robbery on playground" "Argument in school hallway escalated into shooting" ...
 $ Category                                                                                                                                          : chr [1:1556] "Accidental" "Accidental" "Robbery" "Escalation of Dispute" ...
 $ School Type                                                                                                                                       : chr [1:1556] "High" "Junior High" "High" "High" ...
 $ Narrative (Detailed Summary/ Background)                                                                                                          : chr [1:1556] "Student showing off gun cocked hammer and could not get it to release causing accidental discharge and killing "| __truncated__ "14YOM student shot during \"horseplay\" in the school hallway. Friend of the victim surrendered to police." "Group of 10 teens attempted to rob 16YOM (James Owens) on school playground. When victim ran, unknown teen susp"| __truncated__ "Argument between shooter and victim escalated into shooting in school hallway." ...
 $ Sources                                                                                                                                           : chr [1:1556] "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998" "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998 https://www.newspapers.com/image/156467116/?"| __truncated__ "https://www.newspapers.com/image/156467116/?terms=school%2Bshooting" "https://www.newspapers.com/image/18059538/?terms=school%2Bshooting" ...
 $ Time of Occurrence (12 hour AM/PM)                                                                                                                : 'hms' num [1:1556] NA NA NA NA ...
  ..- attr(*, "units")= chr "secs"
 $ Duration (minutes)                                                                                                                                : num [1:1556] 1 1 1 1 NA 8 1 1 NA 1 ...
 $ Day of week (formula)                                                                                                                             : chr [1:1556] "Mon" "Mon" "Mon" "Fri" ...
 $ During School Day (Y/N)                                                                                                                           : logi [1:1556] TRUE TRUE TRUE TRUE FALSE TRUE ...
 $ Time Period                                                                                                                                       : chr [1:1556] NA NA NA NA ...
 $ During a Sporting Event (Y/N)                                                                                                                     : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ During a school sponsored event (school dance, concert, play, activity)                                                                           : chr [1:1556] "No" "No" "No" "No" ...
 $ Location                                                                                                                                          : chr [1:1556] "Inside School Building" "Inside School Building" "Outside on School Property" "Inside School Building" ...
 $ Number of Shots Fired                                                                                                                             : num [1:1556] 1 1 2 4 NA NA 1 1 2 NA ...
 $ Firearm Type                                                                                                                                      : chr [1:1556] "Handgun" "Handgun" "Handgun" "Handgun" ...
 $ Number of Shooters                                                                                                                                : num [1:1556] 1 1 1 1 2 8 1 1 1 2 ...
 $ Shooter Name                                                                                                                                      : chr [1:1556] "Minor" "Minor" "Unknown" "Gertis J. Perry" ...
 $ Shooter Age                                                                                                                                       : num [1:1556] 15 NA NA 18 NA NA 16 18 15 NA ...
 $ Shooter Gender                                                                                                                                    : chr [1:1556] "Male" "Male" "Male" "Male" ...
 $ Race                                                                                                                                              : chr [1:1556] NA NA NA NA ...
 $ Shooter Ethnicity                                                                                                                                 : chr [1:1556] NA NA NA "Not Hispanic or Latino" ...
 $ Shooter's Affiliation with School                                                                                                                 : chr [1:1556] "Student" "Student" "Student" "Student" ...
 $ Shooter had an accomplice who did not fire gun (Y/N)                                                                                              : logi [1:1556] TRUE FALSE TRUE FALSE TRUE TRUE ...
 $ Hostages Taken (Y/N)                                                                                                                              : logi [1:1556] FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ State                                                                                                                                             : chr [1:1556] NA NA NA "Ohio" ...
 $ Date_year                                                                                                                                         : num [1:1556] 1970 1970 1970 1970 1970 1970 1970 1970 1970 1970 ...
 - attr(*, "spec")=
  .. cols(
  ..   Date = col_character(),
  ..   School = col_character(),
  ..   City = col_character(),
  ..   State = col_character(),
  ..   `Reliability Score (1-5)` = col_double(),
  ..   `Killed (includes shooter)` = col_double(),
  ..   Wounded = col_double(),
  ..   `Total Injured/Killed Victims` = col_double(),
  ..   `Gender of Victims (M/F/Both)` = col_character(),
  ..   `Victim's Affiliation w/ School` = col_character(),
  ..   `Victim's age(s)` = col_double(),
  ..   `Victims Race` = col_character(),
  ..   `Victim Ethnicity` = col_character(),
  ..   `Targeted Specific Victim(s)` = col_character(),
  ..   `Random Victims` = col_character(),
  ..   `Bullied (Y/N/ N/A)` = col_character(),
  ..   `Domestic Violence (Y/N)` = col_character(),
  ..   `Suicide (Shooter was only victim) Y/N/ N/A` = col_character(),
  ..   `Suicide (shot self immediately following initial shootings) Y/N/ N/A` = col_character(),
  ..   `Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A` = col_character(),
  ..   `Suicide (or attempted suicide) by Shooter (Y/N)` = col_character(),
  ..   `Shooter's actions immediately after shots fired` = col_character(),
  ..   `Pre-planned school attack` = col_character(),
  ..   Summary = col_character(),
  ..   Category = col_character(),
  ..   `School Type` = col_character(),
  ..   `Narrative (Detailed Summary/ Background)` = col_character(),
  ..   Sources = col_character(),
  ..   `Time of Occurrence (12 hour AM/PM)` = col_time(format = ""),
  ..   `Duration (minutes)` = col_double(),
  ..   `Day of week (formula)` = col_character(),
  ..   `During School Day (Y/N)` = col_character(),
  ..   `Time Period` = col_character(),
  ..   `During a Sporting Event (Y/N)` = col_character(),
  ..   `During a school sponsored event (school dance, concert, play, activity)` = col_character(),
  ..   Location = col_character(),
  ..   `Number of Shots Fired` = col_double(),
  ..   `Firearm Type` = col_character(),
  ..   `Number of Shooters` = col_double(),
  ..   `Shooter Name` = col_character(),
  ..   `Shooter Age` = col_double(),
  ..   `Shooter Gender` = col_character(),
  ..   Race = col_character(),
  ..   `Shooter Ethnicity` = col_character(),
  ..   `Shooter's Affiliation with School` = col_character(),
  ..   `Shooter had an accomplice who did not fire gun (Y/N)` = col_character(),
  ..   `Hostages Taken (Y/N)` = col_character()
  .. )

Geocoding with the ggmap package

To peform the geocoding we need the address of each school in the data set. The data currently does not list the actual address, but does have information about the school where the event occured. Since some schools have the same name, we need the city and state data as well. So we will create a new variable in our data called address using the mutate() function of the dplyr package. This variable will collapse the values in the School, City, and State columns but with spaces in between. It is specified that there will be space in between by the sep = " " argument. Note that a space is typed between the quotation marks. Then we can use the address variable to look up the latitude and longtitude for each school.

Notice that we used a %>% in the previous chunk of code. This allows us to create code with a method called piping.

It allows us to perform many sequential steps efficiently.


Click here if you are unfamiliar with piping in R, which uses this %>% operator.

By piping we mean using the %>% pipe operator which is accessible after loading the tidyverse or several of the packages within the tidyverse like dplyr because they load the magrittr package. This allows us to perform multiple sequential steps on one data input. The object on the left side is used as input to any commands to the right or below.


We can take a look at just this new address variable using the pull() function of the dplyr() package.

Now we can use these addresses to find the latitude and longitude coordinates for each school where a school shooting occured. To do this we will use the geocode function of the ggmap package to look up these addresses on Google Maps to get the latitude and longitude values. In this command we need to specify that we want to use google as the source using the source argument and that we want latitude and longitude using the `output = c(“latlon”) argument.

This step requires registering with the Google Cloud Platform to get an API key, which currently requires registering your payment information and agreeing to the Google Maps API Terms of Service.

Therefore, we will simply demonstrate how this process works in general, but you are not required to do this yourself.

Click here to see how we registered with the Google Cloud Platform.

If you were to do this process yourself, you could get an API key here. Again this requires registering your payment information, but it is free to got an API key and enable the APIs, however you can be billed based on how many addresses you look up using the APIs. You need to look up thousands before getting billed.

Then you need to enable the maps and places APIs, by clicking on the boxes next to each:

Then you would register like so after copying the API key: (Note this is a fake key)


Once we have obtained an API key and registered, we can geocode our data.

Note that this step is time intensive, as there are many addresses to look up! Therefore, we will just show how this is done.

This results in tibble called coords being added to our shooting_data tibble. That’s right we can have a tibble as a column or variable within a tibble. Using the glimpse function again, and looking at the last few variables, we can see that now the last variable listed is coords of class <tibble>.

If we take a look at the first couple of values of the coords tibble, using the slice_head() function of the dplyr package, we see a tibble that looks like this:

It would be better if each of these were their own columns in the tibble, so we will create new longitude and latitude variables again using the mutate function like so:

In this case we use the pull() function to grab the lat and lon variables within the coords tibble which is a variable of the shooting_data tibble.

We can now remove the coords tibble like so, using the select() funtion of the dplyr package:

Now using glimpse() and looking at the last several variables, we can see that we no longer have a coords variable, but we do have two variables calld longitude and latitude that are of class double as indicated by the <dbl>:

Now we will save the geocoded data in the processed_data directory using the write_csv function of the readr package.

This requires listing the R object, followed by the path for where the file should be saved and what it should be called. In this case it will be called “shooting_data.csv”.

Great now we will work with this data, thus you do not need to get an API key to get to this point. We can read our processed geocoded data into R by using the read_csv() function of the readr package.

Need to join our wrangled data with the lat/long data

Geometry lists with the sf package

From this section on, we are now going to use a special pipe operator from the magrittr package called the compound assignment pipe-operator or sometimes the double pipe operator, that looks like this %<>%.

This allows us to use the an input and reassign it at the end after all the subsequent steps have been performed. We can therefore use data_input %<>% instead of data_input <- data_input %>%. We will deomonstrate this in the code below.

We will use the sf (which stands for simple features) package to create what is called a geometry list of our latitude and longitude information for the schools where shootings occured. This will allow us to create a map of these events.

The first thing we need to do is create an sf object (meaning an object that the sf package recognizes) using the st_as_sf() function.

However, to do this we first need to remove rows with NA values for the latitude and longitude variables. In otherwords, we need to remove rows of events that happened at schools with locations that were not identified by google. We can remove this rows using the drop_na() function of the tidyr package. We will use a . to indicate that we want to use the data that we are using as an input with our pipe, but then we will specify that we want to only drop rows were there is an NA value for either the latitude or longitude variables.

[1] 1556   52
# A tibble: 5 x 3
  longitude latitude address                                    
      <dbl>    <dbl> <chr>                                      
1        NA       NA John Marshall High School Los Angeles CA   
2        NA       NA John Marshall High School Los Angeles CA   
3        NA       NA John Marshall High School Los Angeles CA   
4        NA       NA Buell Elementary School Flint MI           
5        NA       NA Country Day High School Estate Concordia VI

Now let’s take a look at the variables in our data related to location by using the select() function of the dplyr package:

# A tibble: 1,551 x 5
   School                         City         State      latitude longitude
   <chr>                          <chr>        <chr>         <dbl>     <dbl>
 1 Hine Junior High School        Washington   <NA>           38.9     -77.0
 2 Sousa Junior High              Washington   <NA>           38.9     -77.0
 3 Unnamed High School            Washington   <NA>           38.9     -77.0
 4 John F. Kennedy High School    Cleveland    Ohio           41.4     -81.6
 5 David Starr Jordan High School Long Beach   California     33.9    -118. 
 6 Pine Bluff Coleman High School Pine Bluff   Arkansas       34.2     -92.1
 7 Pierre S. Dupont High School   Wilmington   Delaware       39.8     -75.5
 8 Carver High School             Delray Beach Florida        26.5     -80.1
 9 Ben Lomond High School         Ogden        Utah           41.3    -112. 
10 Riverside High School          El Paso      Texas          31.7    -106. 
# … with 1,541 more rows

We can see (using the base dim() function) that the dimensions were 1156 rows of 51 variables, but they are now 1551 rows of 50 variables. This is becuase 5 events occured at schools with unidentified complete locations (missing either latitude, longitude, or both).

Now, we are ready to convert our coordinates variables (latitude and longitude) into a coordiante simple feature using the st_as_sf() function. We need to specify what our coordinate variables are and we will also specify what coordinate reference system,(crs) we would like to use. In our case we will use the ESPG reference number 4326, known as ESPG:4326 or the World Geodetic System (WGS) version 84 which is one of the most commonly used CPS and used by by most global positioning systems, known as GPS. This tells R to use the values for the variables called latitude and longitude as latitude and longitude coordinates.

[1] 1551   51

We can see that our latitude and longitude variables were used to create a single new variable called geometry of class <POINT [\(^{\circ}\)]>, thus we have one less column.

In this case, we can take a look at just the first 4 variables and we will also see our last sf variable as well appeneded at the end. So now we can see the variables related to location by simply typing [1:4] next to the name of our tibble shooting_data_geocoded.

Simple feature collection with 1551 features and 4 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -161.7705 ymin: 21.31061 xmax: -68.85822 ymax: 61.23202
CRS:            EPSG:4326
# A tibble: 1,551 x 5
   Date       School                  City       State_abb              geometry
   <date>     <chr>                   <chr>      <chr>               <POINT [°]>
 1 1970-01-05 Hine Junior High School Washington DC         (-76.97829 38.89261)
 2 1970-01-05 Sousa Junior High       Washington DC         (-76.95315 38.88397)
 3 1970-01-05 Unnamed High School     Washington DC         (-76.98263 38.86993)
 4 1970-02-06 John F. Kennedy High S… Cleveland  OH          (-81.57341 41.4425)
 5 1970-03-23 David Starr Jordan Hig… Long Beach CA         (-118.1842 33.87129)
 6 1970-04-15 Pine Bluff Coleman Hig… Pine Bluff AR         (-92.05407 34.21608)
 7 1970-04-22 Pierre S. Dupont High … Wilmington DE         (-75.53298 39.76428)
 8 1970-05-08 Carver High School      Delray Be… FL         (-80.11266 26.45975)
 9 1970-05-15 Ben Lomond High School  Ogden      UT          (-111.951 41.25111)
10 1970-08-28 Riverside High School   El Paso    TX         (-106.3723 31.73379)
# … with 1,541 more rows

Now to allow our points to not overlap for events that took place in the same location, we will add a bit more range so that they don’t overlap one another on our map, we will transform the coordinates using the st_transform() function of the sf package into a two dimensional projection (called the Albers equal-area conic projection) with units in meters using the crs 102008 and then use the st_jitter() of the sf package function to allow a specified amount of range near the actual original GPS coordinates. In this case we will allow for 50 meters of range.

To learn more about geospatial coordinate systems see here and here.

So here we can see the output after transforming our data:

Simple feature collection with 1551 features and 4 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -5937645 ymin: -1635633 xmax: 2001910 ymax: 3621404
CRS:            EPSG:102008
# A tibble: 1,551 x 5
   Date       School                 City       State_abb               geometry
   <date>     <chr>                  <chr>      <chr>                <POINT [m]>
 1 1970-01-05 Hine Junior High Scho… Washington DC            (1544734 24955.29)
 2 1970-01-05 Sousa Junior High      Washington DC            (1546951 24368.15)
 3 1970-01-05 Unnamed High School    Washington DC            (1544919 22266.26)
 4 1970-02-06 John F. Kennedy High … Cleveland  OH              (1129318 256372)
 5 1970-03-23 David Starr Jordan Hi… Long Beach CA          (-1933762 -492186.2)
 6 1970-04-15 Pine Bluff Coleman Hi… Pine Bluff AR          (345345.1 -672058.2)
 7 1970-04-22 Pierre S. Dupont High… Wilmington DE            (1638333 149745.7)
 8 1970-05-08 Carver High School     Delray Be… FL            (1533712 -1445851)
 9 1970-05-15 Ben Lomond High School Ogden      UT           (-1251363 253198.6)
10 1970-08-28 Riverside High School  El Paso    TX         (-937777.2 -916799.7)
# … with 1,541 more rows

And here we can see the output after adding the jitter:

Simple feature collection with 1551 features and 4 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -5937660 ymin: -1635585 xmax: 2001948 ymax: 3621424
CRS:            EPSG:102008
# A tibble: 1,551 x 5
   Date       School                  City       State_abb              geometry
   <date>     <chr>                   <chr>      <chr>               <POINT [m]>
 1 1970-01-05 Hine Junior High School Washington DC           (1544698 24989.46)
 2 1970-01-05 Sousa Junior High       Washington DC           (1546940 24361.85)
 3 1970-01-05 Unnamed High School     Washington DC           (1544891 22302.94)
 4 1970-02-06 John F. Kennedy High S… Cleveland  OH           (1129331 256414.5)
 5 1970-03-23 David Starr Jordan Hig… Long Beach CA         (-1933783 -492218.1)
 6 1970-04-15 Pine Bluff Coleman Hig… Pine Bluff AR         (345361.6 -672044.8)
 7 1970-04-22 Pierre S. Dupont High … Wilmington DE           (1638300 149786.6)
 8 1970-05-08 Carver High School      Delray Be… FL           (1533681 -1445878)
 9 1970-05-15 Ben Lomond High School  Ogden      UT          (-1251385 253186.2)
10 1970-08-28 Riverside High School   El Paso    TX          (-937771 -916760.3)
# … with 1,541 more rows

Notice how the geometry values have changed.

Now we will transform our coordinates back into the 3D latitude and longitude degree system again using the st_transform() function and the ESPG:4326, corrdinate system.

Simple feature collection with 1551 features and 4 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -161.7707 ymin: 21.31038 xmax: -68.85775 ymax: 61.23235
CRS:            EPSG:4326
# A tibble: 1,551 x 5
   Date       School                  City       State_abb              geometry
   <date>     <chr>                   <chr>      <chr>               <POINT [°]>
 1 1970-01-05 Hine Junior High School Washington DC         (-76.97865 38.89296)
 2 1970-01-05 Sousa Junior High       Washington DC          (-76.9533 38.88394)
 3 1970-01-05 Unnamed High School     Washington DC         (-76.98288 38.87028)
 4 1970-02-06 John F. Kennedy High S… Cleveland  OH         (-81.57316 41.44284)
 5 1970-03-23 David Starr Jordan Hig… Long Beach CA         (-118.1844 33.87098)
 6 1970-04-15 Pine Bluff Coleman Hig… Pine Bluff AR         (-92.05388 34.21619)
 7 1970-04-22 Pierre S. Dupont High … Wilmington DE         (-75.53327 39.76468)
 8 1970-05-08 Carver High School      Delray Be… FL         (-80.11302 26.45956)
 9 1970-05-15 Ben Lomond High School  Ogden      UT         (-111.9513 41.25098)
10 1970-08-28 Riverside High School   El Paso    TX         (-106.3723 31.73414)
# … with 1,541 more rows

Notice how the geometry variables are different from what they were orginally with this coordinate system:

Now we will separate the geometry variable into longitude and latitude variables again. We can use the st_coordinates() function of the sf package to extract the coordinates from our tibble as a matrix.

# A tibble: 4 x 2
      X     Y
  <dbl> <dbl>
1 -77.0  38.9
2 -77.0  38.9
3 -77.0  38.9
4 -81.6  41.4

Now, just as we did previously we will create new variables called latitude and longitude from the X and Y variables within the coordinates tibble that is part of our shooting_data_geocoded using the pull() function.

We will also convert our shooting_data_geocoded object which is currently a sf into a tibble using the as_tibble() function of the tibble package and then we will remove the geometry and coordinates variables using the select() function of the dplyr package with a negative sign infront of the names of the variables to remove.

And now we can take a look at our last 3 variables using the last_col() function, which is a select helper function tidyr package. See here for other select helper functions. This allows us to select either the last column, or with a specified offset we can select a number of columns before the last column. Thus 2 columns before the last column would be last_col(offset = 2) and then the : symbol is interpreted as through, thus we are selecting for the third to last column through the last column with last_col(offset = 2): last_col().

# A tibble: 4 x 3
  address                                  longitude latitude
  <chr>                                        <dbl>    <dbl>
1 Hine Junior High School Washington DC        -77.0     38.9
2 Sousa Junior High Washington DC              -77.0     38.9
3 Unnamed High School Washington DC            -77.0     38.9
4 John F. Kennedy High School Cleveland OH     -81.6     41.4

Great! That looks like we expected. We can see that the coordinate values are slightly different now.

# A tibble: 4 x 2
  longitude latitude
      <dbl>    <dbl>
1     -77.0     38.9
2     -77.0     38.9
3     -77.0     38.9
4     -81.6     41.4

tibble [1,551 × 52] (S3: tbl_df/tbl/data.frame)
 $ Date                                                                                                                                              : Date[1:1551], format: "1970-01-05" "1970-01-05" ...
 $ School                                                                                                                                            : chr [1:1551] "Hine Junior High School" "Sousa Junior High" "Unnamed High School" "John F. Kennedy High School" ...
 $ City                                                                                                                                              : chr [1:1551] "Washington" "Washington" "Washington" "Cleveland" ...
 $ State_abb                                                                                                                                         : chr [1:1551] "DC" "DC" "DC" "OH" ...
 $ Reliability Score (1-5)                                                                                                                           : num [1:1551] 3 3 2 2 2 3 3 2 2 2 ...
 $ Killed (includes shooter)                                                                                                                         : num [1:1551] 1 0 0 0 0 1 1 0 0 0 ...
 $ Wounded                                                                                                                                           : num [1:1551] 0 1 0 1 2 5 0 1 2 1 ...
 $ Total Injured/Killed Victims                                                                                                                      : num [1:1551] 1 1 0 1 2 6 1 1 2 1 ...
 $ Gender of Victims (M/F/Both)                                                                                                                      : chr [1:1551] "Male" "Male" "No Victims" "Male" ...
 $ Victim's Affiliation w/ School                                                                                                                    : chr [1:1551] "Student" "Student" "No Victims" "Student" ...
 $ Victim's age(s)                                                                                                                                   : num [1:1551] 15 NA NA 18 NA NA 18 19 NA 15 ...
 $ Victims Race                                                                                                                                      : chr [1:1551] NA NA "No Victims" NA ...
 $ Victim Ethnicity                                                                                                                                  : chr [1:1551] NA NA "No Victims" NA ...
 $ Targeted Specific Victim(s)                                                                                                                       : chr [1:1551] "No" "No" "Yes" "Yes" ...
 $ Random Victims                                                                                                                                    : chr [1:1551] "Yes" "Yes" "No" "No" ...
 $ Bullied (Y/N/ N/A)                                                                                                                                : chr [1:1551] "No" "No" "No" "No" ...
 $ Domestic Violence (Y/N)                                                                                                                           : chr [1:1551] "No" "No" "No" "No" ...
 $ Suicide (Shooter was only victim) Y/N/ N/A                                                                                                        : chr [1:1551] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (shot self immediately following initial shootings) Y/N/ N/A                                                                              : chr [1:1551] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A: chr [1:1551] "N/A" "N/A" "N/A" "N/A" ...
 $ Suicide (or attempted suicide) by Shooter (Y/N)                                                                                                   : chr [1:1551] "No" "No" "No" "No" ...
 $ Shooter's actions immediately after shots fired                                                                                                   : chr [1:1551] "Unknown if Subdued Surrendered or Fled" "Immediately Surrendered" "Fled" "Unknown if Subdued Surrendered or Fled" ...
 $ Pre-planned school attack                                                                                                                         : chr [1:1551] "No" "No" "No" "No" ...
 $ Summary                                                                                                                                           : chr [1:1551] "Didn't know how to operate pistol, cocked hammer and couldn't get it to safely release causing accidental discharge" "Occurred during horseplay in the school" "Student shot at twice during attempted robbery on playground" "Argument in school hallway escalated into shooting" ...
 $ Category                                                                                                                                          : chr [1:1551] "Accidental" "Accidental" "Robbery" "Escalation of Dispute" ...
 $ School Type                                                                                                                                       : chr [1:1551] "High" "Junior High" "High" "High" ...
 $ Narrative (Detailed Summary/ Background)                                                                                                          : chr [1:1551] "Student showing off gun cocked hammer and could not get it to release causing accidental discharge and killing "| __truncated__ "14YOM student shot during \"horseplay\" in the school hallway. Friend of the victim surrendered to police." "Group of 10 teens attempted to rob 16YOM (James Owens) on school playground. When victim ran, unknown teen susp"| __truncated__ "Argument between shooter and victim escalated into shooting in school hallway." ...
 $ Sources                                                                                                                                           : chr [1:1551] "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998" "https://news.google.com/newspapers?id=AfRYAAAAIBAJ&pg=3025,1894998 https://www.newspapers.com/image/156467116/?"| __truncated__ "https://www.newspapers.com/image/156467116/?terms=school%2Bshooting" "https://www.newspapers.com/image/18059538/?terms=school%2Bshooting" ...
 $ Time of Occurrence (12 hour AM/PM)                                                                                                                : 'hms' num [1:1551] NA NA NA NA ...
  ..- attr(*, "units")= chr "secs"
 $ Duration (minutes)                                                                                                                                : num [1:1551] 1 1 1 1 NA 8 1 1 NA 1 ...
 $ Day of week (formula)                                                                                                                             : chr [1:1551] "Mon" "Mon" "Mon" "Fri" ...
 $ During School Day (Y/N)                                                                                                                           : chr [1:1551] "Yes" "Yes" "Yes" "Yes" ...
 $ Time Period                                                                                                                                       : chr [1:1551] NA NA NA NA ...
 $ During a Sporting Event (Y/N)                                                                                                                     : chr [1:1551] "No" "No" "No" "No" ...
 $ During a school sponsored event (school dance, concert, play, activity)                                                                           : chr [1:1551] "No" "No" "No" "No" ...
 $ Location                                                                                                                                          : chr [1:1551] "Inside School Building" "Inside School Building" "Outside on School Property" "Inside School Building" ...
 $ Number of Shots Fired                                                                                                                             : num [1:1551] 1 1 2 4 NA NA 1 1 2 NA ...
 $ Firearm Type                                                                                                                                      : chr [1:1551] "Handgun" "Handgun" "Handgun" "Handgun" ...
 $ Number of Shooters                                                                                                                                : num [1:1551] 1 1 1 1 2 8 1 1 1 2 ...
 $ Shooter Name                                                                                                                                      : chr [1:1551] "Minor" "Minor" "Unknown" "Gertis J. Perry" ...
 $ Shooter Age                                                                                                                                       : num [1:1551] 15 NA NA 18 NA NA 16 18 15 NA ...
 $ Shooter Gender                                                                                                                                    : chr [1:1551] "Male" "Male" "Male" "Male" ...
 $ Race                                                                                                                                              : chr [1:1551] NA NA NA NA ...
 $ Shooter Ethnicity                                                                                                                                 : chr [1:1551] NA NA NA "Not Hispanic or Latino" ...
 $ Shooter's Affiliation with School                                                                                                                 : chr [1:1551] "Student" "Student" "Student" "Student" ...
 $ Shooter had an accomplice who did not fire gun (Y/N)                                                                                              : chr [1:1551] "Yes" "No" "Yes" "No" ...
 $ Hostages Taken (Y/N)                                                                                                                              : chr [1:1551] "No" "No" "No" "No" ...
 $ State                                                                                                                                             : chr [1:1551] NA NA NA "Ohio" ...
 $ Date_year                                                                                                                                         : num [1:1551] 1970 1970 1970 1970 1970 1970 1970 1970 1970 1970 ...
 $ address                                                                                                                                           : chr [1:1551] "Hine Junior High School Washington DC" "Sousa Junior High Washington DC" "Unnamed High School Washington DC" "John F. Kennedy High School Cleveland OH" ...
 $ longitude                                                                                                                                         : num [1:1551] -77 -77 -77 -81.6 -118.2 ...
 $ latitude                                                                                                                                          : num [1:1551] 38.9 38.9 38.9 41.4 33.9 ...
 - attr(*, "spec")=
  .. cols(
  ..   Date = col_date(format = ""),
  ..   School = col_character(),
  ..   City = col_character(),
  ..   State_abb = col_character(),
  ..   `Reliability Score (1-5)` = col_double(),
  ..   `Killed (includes shooter)` = col_double(),
  ..   Wounded = col_double(),
  ..   `Total Injured/Killed Victims` = col_double(),
  ..   `Gender of Victims (M/F/Both)` = col_character(),
  ..   `Victim's Affiliation w/ School` = col_character(),
  ..   `Victim's age(s)` = col_double(),
  ..   `Victims Race` = col_character(),
  ..   `Victim Ethnicity` = col_character(),
  ..   `Targeted Specific Victim(s)` = col_character(),
  ..   `Random Victims` = col_character(),
  ..   `Bullied (Y/N/ N/A)` = col_character(),
  ..   `Domestic Violence (Y/N)` = col_character(),
  ..   `Suicide (Shooter was only victim) Y/N/ N/A` = col_character(),
  ..   `Suicide (shot self immediately following initial shootings) Y/N/ N/A` = col_character(),
  ..   `Suicide (e.g., shot self at end of incident - time period between first shots and suicide, different location, when confronted by police) Y/N/ N/A` = col_character(),
  ..   `Suicide (or attempted suicide) by Shooter (Y/N)` = col_character(),
  ..   `Shooter's actions immediately after shots fired` = col_character(),
  ..   `Pre-planned school attack` = col_character(),
  ..   Summary = col_character(),
  ..   Category = col_character(),
  ..   `School Type` = col_character(),
  ..   `Narrative (Detailed Summary/ Background)` = col_character(),
  ..   Sources = col_character(),
  ..   `Time of Occurrence (12 hour AM/PM)` = col_time(format = ""),
  ..   `Duration (minutes)` = col_double(),
  ..   `Day of week (formula)` = col_character(),
  ..   `During School Day (Y/N)` = col_character(),
  ..   `Time Period` = col_character(),
  ..   `During a Sporting Event (Y/N)` = col_character(),
  ..   `During a school sponsored event (school dance, concert, play, activity)` = col_character(),
  ..   Location = col_character(),
  ..   `Number of Shots Fired` = col_double(),
  ..   `Firearm Type` = col_character(),
  ..   `Number of Shooters` = col_double(),
  ..   `Shooter Name` = col_character(),
  ..   `Shooter Age` = col_double(),
  ..   `Shooter Gender` = col_character(),
  ..   Race = col_character(),
  ..   `Shooter Ethnicity` = col_character(),
  ..   `Shooter's Affiliation with School` = col_character(),
  ..   `Shooter had an accomplice who did not fire gun (Y/N)` = col_character(),
  ..   `Hostages Taken (Y/N)` = col_character(),
  ..   State = col_character(),
  ..   Date_year = col_double(),
  ..   address = col_character(),
  ..   longitude = col_double(),
  ..   latitude = col_double()
  .. )
 - attr(*, "sf_column")= chr "geometry"
 - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA NA ...
  ..- attr(*, "names")= chr [1:53] "Date" "School" "City" "State_abb" ...

Looks good!

Now we will save our wrangled data, again using write_csv().

from Michael:

INTRODUCE THE CONCEPT OF DASHBOARDS

INTRODUCE flexdashboard

Data Analysis and Visualization


First let’s load the data by reading in our wrangled version of the data.

There are several elements we would like to include in our dashboard.

One thing we would like is an interactive table.

We can done so using the datatable() function of the DT package.

This creates a searchable table and the order in which the data is displayed can be toggled to change for each variable.

However, we have many varaibles, so this get’s to be overwhelming. Since there are so many this even modifies the way the rmarkdown for this case study is rendered, thus instead of displaying all of the variables, let’s choose only some of the most interesting to display on our dashboard.

Now we would also like to make some visualizations of our data.

Yearly Deaths

First, we would like to create a plot of the number of shootings per year.

To do this we will first count the number of shootings per year by using the group_by() function and the count() function of the dplyr package. The group_by() functions allows us to summarize the data across specific groups specified by a variable or multiple variables. By grouping by Date_year we can then use the count() function to count the number of rows with shooting event information for each unique value of the Date_year variable.

We then want to use the ungroup() function to get the data out of this grouping based on the Data_year varaible.

# A tibble: 51 x 2
   Date_year     n
       <dbl> <int>
 1      1970    20
 2      1971    21
 3      1972    18
 4      1973    18
 5      1974    16
 6      1975    14
 7      1976    11
 8      1977    16
 9      1978    16
10      1979    14
# … with 41 more rows

Nice looks good!

Now to make a plot of this data we will use the ggplot2 package.

Click here for an introduction about this package if you are new to using ggplot2

The ggplot2 package is generally intuitive for beginners because it is based on a grammar of graphics or the gg in ggplot2. The idea is that you can construct many sentences by learning just a few nouns, adjectives, and verbs. There are specific “words” that we will need to learn and once we do, you will be able to create (or “write”) hundreds of different plots.

The critical part to making graphics using ggplot2 is the data needs to be in a tidy format. Given that we have just spent time putting our data in tidy format, we are primed to take advantage of all that ggplot2 has to offer!

We will show how it is easy to pipe tidy data (output) as input to other functions that create plots. This all works because we are working within the tidyverse.

What is the ggplot() function? As explained by Hadley Wickham:

The grammar tells us that a statistical graphic is a mapping from data to aesthetic attributes (colour, shape, size) of geometric objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinates system.

ggplot2 Terminology:

  • ggplot - the main function where you specify the dataset and variables to plot (this is where we define the x and y variable names)
  • geoms - geometric objects
    • e.g. geom_point(), geom_bar(), geom_line(), geom_histogram()
  • aes - aesthetics
    • shape, transparency, color, fill, line types
  • scales - define how your data will be plotted
    • continuous, discrete, log, etc

The function aes() is an aesthetic mapping function inside the ggplot() object. We use this function to specify plot attributes (e.g. x and y variable names) that will not change as we add more layers.

Anything that goes in the ggplot() object becomes a global setting. From there, we use the geom objects to add more layers to the base ggplot() object. These will define what we are interested in illustrating using the data.


For more of an introduction on creating plots with ggplot2 , see this case study

First, we start with the ggplot() function of the ggplot2 package.

This function requires that the aesthetics aes() be specified. This involves choosing what variable will be plotted on the x-axis and the y axis.

This will create an empty plot area, next we need to use one of the geom* functions of the ggplot2 package to specify what type of plot we want to create.

Type geom into the RStudio console and you will see many options to scroll through.

We will be creating a geom_col() plot, which is a particular type of bar plot that uses the acutal values to plot, rather than counts, which is the default of geom_bar() We will specify with the fill argument, that we want our bars to be filled with the color black.

We will also modify the x-axis using the scale_x_continuous() function. This function allows for specification of the range or limits of the axis using the limits argument. We can use the base seq() function to create a sequence of numbers for each tick mark.

We can add labels to our plot using the labs() function of ggplot2. This has arguments such as x and y for the axes and title and subtitle for titles.

We will also modify the overall aesthetics of the plot using a theme_* function. See here for a list of options.

Yearly Cumulative Deaths

Now let’s make another plot of the cumulative deaths each year including those of the previous years. In this case we can use the shooting_per_year object that we previously made. We want to add a new variable using the mutate function called n_cum_sum by using the cumsum() function to calculate a cumulative sum based on the yearly count.

# A tibble: 51 x 2
   Date_year     n
       <dbl> <int>
 1      1970    20
 2      1971    21
 3      1972    18
 4      1973    18
 5      1974    16
 6      1975    14
 7      1976    11
 8      1977    16
 9      1978    16
10      1979    14
# … with 41 more rows
# A tibble: 51 x 3
   Date_year     n n_cumsum
       <dbl> <int>    <int>
 1      1970    20       20
 2      1971    21       41
 3      1972    18       59
 4      1973    18       77
 5      1974    16       93
 6      1975    14      107
 7      1976    11      118
 8      1977    16      134
 9      1978    16      150
10      1979    14      164
# … with 41 more rows

Great, this looks like we would expect!

Now let’s make a plot like we did before:

Deaths per Shooting

Now, lets make a plot of the number of deaths per shooting based on the Killed (includes shooter) varaible. Our first plot could also have been made using geom_bar() instead of geom_col() this makes a similar plot but automatically uses the count for one of the axes.

It is a bit difficult to see the shootings that had more numerious deaths, so we will add a facet that zooms in on this portion of the plot. We can do so, using the facet_zoom() function of the ggforce package.

Killed (includes shooter)                num_events                   percent 
               85.0000000                12.0000000                 0.7712082 
[1] "85 deaths"

avocado! columbine - which had 12 deaths is not included…

also better to plot differently to show high values - maybe a zoom

Dashboard


RA NOTES

General Notes

Consult this document for a general overview:

  • case-study-structure-MO-notes

There are several datasets involved in this case study

  • Raw dataset (raw_data/K-12 SSDB (Public) - K-12 SSDB (Public) Linked.csv)
  • Geocoded dataset (processed_data/shooting_data.csv)
  • Wrangled dataset (processed_data/shooting_data_wrangled)

This document uses the geocoded dataset to produce the wrangled dataset.

The wrangled dataset is then used to produce the dashboard in the other document.

Code to geocode and then wrangle the datasets are included in this document.

The goecoding required to produce this case study took approximately 1.5-2 hours on a Macbook Air (2015).

The maps we created were largely restrictred to efficient maps. Maps with multiple layers required a lot of computational power which we chose not to use.

Metadeta

Flexdashboard requires metadeta to work. A good example of what we did can be found on the layout section of the RStudio/flexdashboard/Home link included above.

Columns & Rows

In the metadata, we specify whether we want our output to be oriented in rows (left to right) or columns (top to bottom). If I created two plots with columnwise settings, the first plot will be at the top and the second at the bottom. If I do the same thing for rowwise settigns, the first plot will be on the left and the second plot will be on the right. Each time we specify a new column or row, the output is shown in this way in a specific column/row. See Multiple Columns and Row Orientation on the RStudio/flexdashboard/Home link included above for an example.

We specify a column/row with this.

-------------------------------------

It does not matter whether you write column/row above that. The only thing that matters is the orientation set-up in the metadeta.

orientation: columns is the default from my understanding.

You need to specify orientation: rows if you want rowwise orientation

You can add tabsets to columns/rows with:

Column {.tabset}

See the Tabsets section on RStudio/flexdashboard/Using for clear examples of how this can be done.

Graphics & Titles

Most plots can be plotted by specifying a title chunk with the title specified.

Shiny

Shiny can be used with flexdashboard. Coding with packages that have shiny functionality requires shiny-specific code is shiny is enabled. In our case, shiny is enabled. Packages such as DT or Leaflet may operate differently as a result.

Leaflet

Leaflet widgets can be included within dashboards created with flexdashboard.

Leaflet works by provided by adding base data (such as a map) and then adding markers if desired in layers. This is very similar to how ggplot functions (pun intended).

The layers displayed can be controlled using a sort of legend. Depending on the type of layers, some information may be displayed mutually exclusive of the other layers; other layers (such as circles/general markers) can be toggled on and off.

A minimap can be added.

The layers displayed when the widget is first opened can also be controlled. We did that in this case study.

groups in leaflet can be thought of as layer-specific IDs that create labels for legends and allow specific layers to be referred to in separate functions.

If we called a group “Layer 1” and then in a subsequent layer referred to “Layer 1”, Leaflet will correctly identify which layer is being referenced.

Leaflet can require a lot of computational power; this can have an impact on the types of maps produced.

Clustering options can be applied to circles/markers. Some examples of this can be found on the bottom of this page.

### Specified Title

If the title is unspecified…

###

the graphics will be recognized but no title will be shown for that particular graphic.

fig-width and fig.height operate in the code chunk options.

RA Code

We will employ the following layout for the dashboard.

RMarkdown Dashboard Structure

  • Icon (48 x 48)
  • The Data
  • Column 1: Interactive Table
  • Column 2: Photo
  • US Statistics
  • Column 1
  • Yearly Deaths
  • Yearly Cumulative Deaths
  • Deaths per Shooting
  • Column 2
  • Wounded
  • Deaths
  • Shooting Completed/Attempted Suicide
  • Median Shots Fired
  • Deaths, Shooter was Only Victim
  • Use of a Single Handgun
  • State Statistics
  • Sidebar
  • Column 1
  • Yearly Deaths
  • Yearly Cumulative Deaths
  • Deaths per Shooting
  • Map
  • Zoom (+)
  • Zoom (-)
  • Layer Controls
  • Provider Tiles
  • Circle Markers
  • Mini-map
  • About
  • Column 1
  • Disclaimer
  • How do I use this dashboard?
  • Does Open Case Studies have more resources I can access to learn about creating this dashboard?
  • Column 2: Photo
  • Tutorial
  • Step 1: Load the flexdashboard package
  • Step 2: Create and RMD document
  • Step 3: Create an appropriate YAML.
  • Step 4: Design the layout of the dashboard.
  • Step 5: Add content to the dashboard.
  • Hotline
  • Warning Signs
  • Response to Warning Signs
  • Source Code

We create the The Data page.

Column {data-width=700}
-------------------------------------

The data is from the K-12 school shooting database. This database was compiled using several steps to identify and authenticate incidents. Methods are outlined [here](https://www.chds.us/ssdb/methods/).

The database includes a codebook that defines each variable.

###

We then insert an interactive table. Since we have shiny enabled, we need to use DF::renderDataTable to produce the output we desire.

In a separate column, we will add a relevant photo to approve the visual appeal of the dashboard. Note that the width of this column is set to 300. Size specifications on flexdashboard are unitless; the width of any column included on a page is a function of the width set for a column against the sum of widths for all columns on that page. If we set columns sizes of 600 and 300 on a page with two columns, one column will be twice as large as the other column.

We include a figure caption to credit the author of the photograph.

Note that there is no text next to the area where we would normally specify a header. In this case, no header is necessary for this content. flexdashboard & RMarkdown recognize this and removes the header option.

Column {data-width=300}
-------------------------------------

###

'''{r, echo=FALSE, fig.cap="[Photograph by Rubén Rodriguez](https://unsplash.com/photos/IXTvnOOSTyU)", out.width = '100%'}
knitr::include_graphics("ruben-rodriguez-IXTvnOOSTyU-unsplash.jpg")
'''

Let’s create a page for US Statistics we would like to share.

US Statistics {data-icon="fa-flag"}
===================================== 

Let’s create a column. Note the .tabset and .tabset-fade options specified for the column.

Column {data-width=700 .tabset .tabset-fade}
-------------------------------------

After having specified the .tabset and .tabset-fade options, we can create each tab in the same way we would create columns.

### Yearly Deaths

'''{r}
shooting_data_geocoded_us <- shooting_data_geocoded %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) %>%
    mutate(Date_year = year(Date)) %>%
    group_by(Date_year) %>%
    count() %>%
    ungroup()
start <- 1970
end <- 2020
shooting_data_geocoded_us %>%
    ggplot(aes(x = Date_year, y = n)) +
    geom_bar(stat = "identity", fill = "black") +
    scale_x_continuous(breaks = seq(start, end, by = 5),
                 labels = seq(start, end, by = 5),
                 limits = c(start-1, end+1)) +
    theme_minimal() +
    labs(title = "Yearly Deaths Attributable to School Shootings",
         subtitle = "United States",
         x = "School Shootings",
         y = "")
'''

### Yearly Cumulative Deaths

'''{r}
start <- 1970
end <- 2020
shooting_data_geocoded_us2 <- shooting_data_geocoded %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) %>%
    mutate(Date_year = year(Date)) %>%
    group_by(Date_year) %>%
    summarize(N = n()) %>%
    ungroup() %>%
    complete(Date_year = seq(start,end,by=1)) %>%
    mutate(n_cumsum = cumsum(N))
shooting_data_geocoded_us2 %>%
    ggplot(aes(x = Date_year, y = n_cumsum)) +
    geom_bar(stat = "identity", fill = "black") +
    scale_x_continuous(breaks = seq(start, end, by = 5),
                 labels = seq(start, end, by = 5),
                 limits = c(start-1, end+1)) +
    theme_minimal() +
    labs(title = "Yearly Cumulative Deaths Attributable to School Shootings",
         subtitle = "United States",
         x = "School Shootings",
         y = "")
'''

### Deaths per Shooting

'''{r}
shooting_data_geocoded_us3 <- shooting_data_geocoded %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) %>%
    mutate(Date_year = year(Date)) %>%
    group_by(`Killed (includes shooter)`) %>%
    summarize(N = n())
shooting_data_geocoded_us3 %>%
    ggplot(aes(x = `Killed (includes shooter)`, y = N)) +
    geom_bar(stat = "identity", fill = "black") +
  scale_x_continuous(breaks = seq(0,10, by = 1),
                     labels = seq(0,10, by = 1),
                     limits = c(-1,10)) +
  scale_y_continuous() +
    theme_minimal() +
    labs(title = "Deaths per School Shooting",
         subtitle = "United States",
         x = "School Shootings",
         y = "")
'''

We include a column for value boxes.

Column {data-width=300}
------------------------------------- 

We create the first value box. We want to display some important statistics, importantly:

  • Wounded
  • Deaths
  • Shooting Completed/Attempted Suicide
  • Median Shots Fired
  • Deaths, Shooter was Only Victim
  • Use of a Single Handgun
### **Wounded**
    
'''{r}
valueBox(sum(shooting_data_geocoded$Wounded, na.rm = TRUE),
         color = "white")
'''

We create the remaining value boxes

### **Deaths**

'''{r}
valueBox(sum(shooting_data_geocoded$`Killed (includes shooter)`, na.rm = TRUE),
         color = "white")
'''

### **Shooter Completed/Attempted Suicide**

'''{r}
# this needs to be wrangled in the regular data
suicide <- shooting_data_geocoded %>%
  mutate(`Suicide (or attempted suicide) by Shooter (Y/N)` = case_when(`Suicide (or attempted suicide) by Shooter (Y/N)` == "Yes" ~ TRUE,
                                                                       TRUE ~ FALSE)) %>%
  pull(`Suicide (or attempted suicide) by Shooter (Y/N)`)

suicide <- sum(suicide,
               na.rm = TRUE) / length(suicide)

# valueBox(
#   paste(
#     round(
#       mean(suicide,
#            na.rm = TRUE) * 100,
#       2),
#     "%"),
#   color = "white")

valueBox(
  paste(
    round(suicide * 100,
          2),
  "%"),
  color = "white")
'''

### **Median Shots Fired**

'''{r}
valueBox(
  round(
  median(shooting_data_geocoded$`Number of Shots Fired`,
      na.rm = TRUE),
  2),
  color = "white")
'''

### **Deaths, Shooter was Only Victim**

'''{r}
valueBox(
  paste(
    as.character(
    round(
      100 * (sum(
    ifelse(shooting_data_geocoded$`Suicide (Shooter was only victim) Y/N/ N/A` == "Y",
                TRUE,
                FALSE), na.rm = TRUE)
    /
      sum(shooting_data_geocoded$`Killed (includes shooter)`, na.rm = TRUE)),
    2)), "%"),
  color = "white")
'''

### **Use of a Single Handgun**

'''{r}
valueBox(
  paste(
    as.character(
    round(
      100 * (sum(
    ifelse(shooting_data_geocoded$`Firearm Type` == "Rifle",
                TRUE,
                FALSE), na.rm = TRUE)
    /
      length(shooting_data_geocoded$`Firearm Type`)),
    2)), "%"),
  color = "white")
'''

We then create the next page, State Statistics

State Statistics {data-icon=fa-flag-checkered}
===================================== 

Column {.sidebar data-width=250}
-----------------------------------------------------------------------

'''{r}
selectInput("state_selected", label = "Select a state to explore:",
            choices = unique(map_data("state") %>%
                               filter(region!="district of columbia") %>%
                               pull(region)) %>%
              str_to_title(), selected = "Maryland")
'''

Column {data-width=750 .tabset .tabset-fade}
-----------------------------------------------------------------------

### Yearly Deaths

'''{r}
renderPlot({
  start <- 1970
  end <- 2020
  state_df <- as_tibble(cbind(state.abb, state.name))
  shooting_data_geocoded <- shooting_data_geocoded %>%
    rename("State_abb" = State) %>%
    left_join(state_df, by = c("State_abb" = "state.abb")) %>%
    rename("State" = state.name) %>%
    mutate(State = str_to_title(tolower(State))) %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) # this must be applied to wrangling
  shooting_data_geocoded_f <- shooting_data_geocoded[shooting_data_geocoded$State == input$state_selected, ]
  shooting_data_geocoded_f <- shooting_data_geocoded_f %>%
    mutate(Date_year = year(Date)) %>%
    group_by(Date_year) %>%
    count() %>%
    ungroup()
  shooting_data_geocoded_f %>%
    ggplot(aes(x = Date_year, y = n)) +
    geom_bar(stat = "identity", fill = "black") +
    scale_x_continuous(breaks = seq(start, end, by = 5),
                 labels = seq(start, end, by = 5),
                 limits = c(start-1, end+1)) +
    theme_minimal() +
    labs(title = "Statewide School Shootings",
         subtitle = input$state_selected,
         x = "Yearly Deaths Attributable to School Shootings",
         y = "")
})
'''

### Yearly Cumulative Deaths

'''{r}
renderPlot({
  start <- 1970
  end <- 2020
  state_df2 <- as_tibble(cbind(state.abb, state.name))
  shooting_data_geocoded2 <- shooting_data_geocoded %>%
    rename("State_abb" = State) %>%
    left_join(state_df2, by = c("State_abb" = "state.abb")) %>%
    rename("State" = state.name) %>%
    mutate(State = str_to_title(tolower(State))) %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) # this must be applied to wrangling
  shooting_data_geocoded_f2 <- shooting_data_geocoded2[shooting_data_geocoded2$State == input$state_selected, ]
  shooting_data_geocoded_f2 <- shooting_data_geocoded_f2 %>%
    mutate(Date_year = year(Date)) %>%
    group_by(Date_year) %>%
    summarize(N = n()) %>%
    ungroup() %>%
    complete(Date_year = seq(start, end, by=1),
             fill = list(N = 0)) %>%
    mutate(n_cumsum = cumsum(N))
  shooting_data_geocoded_f2 %>%
    ggplot(aes(x = Date_year, y = n_cumsum)) +
    geom_bar(stat = "identity", fill = "black") +
    scale_x_continuous(breaks = seq(start, end, by = 5),
                 labels = seq(start, end, by = 5),
                 limits = c(start-1, end+1)) +
    theme_minimal() +
    labs(title = "Yearly Cumulative Deaths Attributable to School Shootings",
         subtitle = input$state_selected,
         x = "School Shootings",
         y = "")
})
'''

### Deaths per Shooting

'''{r}
renderPlot({
  state_df3 <- as_tibble(cbind(state.abb, state.name))
  shooting_data_geocoded3 <- shooting_data_geocoded %>%
    rename("State_abb" = State) %>%
    left_join(state_df3, by = c("State_abb" = "state.abb")) %>%
    rename("State" = state.name) %>%
    mutate(State = str_to_title(tolower(State)))
  shooting_data_geocoded3 <- shooting_data_geocoded3 %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y")) %>%
    mutate(Date_year = year(Date)) %>%
    group_by(State,`Killed (includes shooter)`) %>%
    summarize(N = n())
  shooting_data_geocoded_f3 <- shooting_data_geocoded3[shooting_data_geocoded3$State == input$state_selected, ]
  shooting_data_geocoded_f3 %>%
    ggplot(aes(x = `Killed (includes shooter)`, y = N)) +
    geom_bar(stat = "identity", fill = "black") +
  scale_x_continuous(breaks = seq(0,30, by = 1),
                     labels = seq(0,30, by = 1),
                     limits = c(-1,30)) +
  scale_y_continuous() +
    theme_minimal() +
    labs(title = "Deaths per School Shooting",
         subtitle = input$state_selected,
         x = "School Shootings",
         y = "")
})
'''

We then create the Map page.

Column {data-width=1000}
------------------------------------- 
    
### 
    
'''{r}
# would be a great idea to add a slider here if possible
# good site for icons https://iconarchive.com/

shooting_information0 <- paste('<div style="height:auto;line-height:1em;overflow:visible;padding:5px;">',
                              shooting_data_geocoded$Date,
                              "<b>",
                              shooting_data_geocoded$School,
                              "</b>",
                              shooting_data_geocoded$`Narrative (Detailed Summary/ Background)`,
                              "</div>",
                              sep = "<br/>"
)

# icon_set <- icons(
#   iconUrl = case_when(shooting_data_geocoded$`Firearm Type`=="Handgun" ~ "https://icons.iconarchive.com/icons/icons8/windows-8/48/Military-Gun-icon.png",
#                       shooting_data_geocoded$`Firearm Type`=="Rifle" ~ "https://icons.iconarchive.com/icons/icons8/windows-8/48/Military-Rifle-icon.png",
#                       TRUE ~ "https://icons.iconarchive.com/icons/dryicons/aesthetica-2/48/page-search-icon.png"),
#   iconWidth = 20,
#   iconHeight = 20
# )

leaflet(shooting_data_geocoded) %>%
  addProviderTiles(provider = providers$OpenStreetMap, group = "OpenStreetMap") %>%
  addProviderTiles(provider = providers$Esri.WorldImagery, group = "ESRI World Imagery") %>%
  addProviderTiles(provider = providers$Stamen.TonerLite, group = "Toner Lite") %>%
  addCircleMarkers(popup = ~shooting_information0,
                   lng = ~longitude,
                   lat = ~latitude,
    radius = 5,
    color = "red",
    fillOpacity = 0.2,
    stroke = TRUE,
    clusterOptions = markerClusterOptions(),
    group = "Circles") %>%
  # addMarkers(lng = ~longitude,
  #                  lat = ~latitude,
  #            popup = ~shooting_information0,
  #                  icon = icon_set,
  #                  group = "TESTER") %>%
  addMiniMap(tiles = providers$Stamen.Toner,
             toggleDisplay = TRUE,
             minimized = FALSE) %>%
  addLayersControl(
    baseGroups = c("Toner Lite",
                   "OpenStreetMap",
                   "ESRI World Imagery"),
    overlayGroups = c("Circles"),
    # overlayGroups = c("Circles", "TESTER"),
    options = layersControlOptions(collapsed = TRUE)
  ) %>%
  setView(lng = -98.35, lat = 39.5, zoom = 4)
# hideGroup(c("Circles", "TESTER"))
# need to jitter coordinates by a few meters for repeats
'''

We then create the About page.

About {data-icon="fa-question-circle"}
===================================== 

Column {data-width=700}
-------------------------------------

###

**What is the purpose of this dashboard?**

This dashboard has two purposes:

+ Illustrate trends in school shootings
+ Demonstrate how to create a dashboard using `R`

**I want to learn how to create a dashboard just like this.**

Visit the *Tutorial* page of this dashboard to first learn the basics about building a dashboard.

At the end of the tutorial we provide a link to this [supplementary resource by the Open Case Studies project](INCLUDE LINK HERE).

We have included the source code (see upper right-hand corner) in this dashboard for more experienced `R` users looking to mimic some of what we did in this dashboard in their own.

**Disclaimer**

The purpose of the [Open Case Studies](https://opencasestudies.github.io){target="_blank"} project is **to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data**.

A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts. 

Column {data-width=300}
-------------------------------------

###

'''{r, echo=FALSE, fig.cap="[Photograph by Rubén Rodriguez](https://unsplash.com/photos/IXTvnOOSTyU)", out.width = '100%'}
knitr::include_graphics("nathan-dumlao-xPHmmVKS8lM-unsplash.jpg")
'''

We create a Tutorial page that links to this resource.

Tutorial {.storyboard data-icon="fa-list-ol"}
=========================================   

### **1)** Load the `flexdashboard` package.

Install the package if you don't have the package installed already

'''{r, echo=TRUE, eval=FALSE}
install.packages("flexdashboard")
install.packages("shiny")
'''

Once installed, the package is ready to be loaded into the `R` environment.

'''{r, echo=TRUE}
library(flexdashboard)
library(shiny)
'''

This all needs to be done separately in the `R` console.

### **2)** Create an `RMD` document.   

Dashboards can be created with `flexdashboard` in the `HTML` format. 

`flexdashboard` uses `RMarkdown` to produce dashboards that can contain `R` output.

This makes it possible to include several mediums in our dashboard such as plots created with `ggplot` or maps created with `leaflet`.
    
### **3)** Create an appropriate `YAML`.

The use of `flexdashboard` alters the way `RMarkdown` documents function. These altered functions are largely dependent on the metadata we use to produce the dashboard. Metadata for the dashboard can be configured in the `YAML` of the `RMD`. 

An `HTML` document created with `RMarkdown` includes a `YAML` that is some variation of this:

'''
---
title: "Untitled"
author: "Michael Ontiveros"
date: "8/12/2020"
output: html_document
---
'''

We used the following `YAML` for this dashboard:

'''
output: 
  flexdashboard::flex_dashboard:
    logo: https://icons.iconarchive.com/icons/icons8/windows-8/48/Programming-Dashboard-icon.png
    theme: readable
    orientation: columns
    source: embed
    vertical_layout: fill
runtime: shiny
'''

We introduce an icon, provide a theme with a color scheme, define the orientation (and thus order) of coded output, include the code used, limit scrolling, and allow `shiny` widgets to be used.

### **4)** Design the layout of the dashboard.

Dashboards are inherently visual, making this step the most time intensive after content creation. We need to present the data in a way that is both meaning and visually appealing.

On this dashboard, we wanted to present static plots of the United States and of individual states. We also wanted to display the locations of school shootings and provide some information about school shootings. Aside from being a dashboard, we wanted to create an educational resource that was reproducible for others. Lastly, as a sensitive topic, we wanted to raise awareness and provide information that could help others act.

Given these goals, we decided on the following page layout:

+ The Data
+ US Statistics
+ State Statistics
+ Map
+ About
+ Tutorial
+ Hotline
+ Source Code

This layout ensured that we did to not include too many components.

The first page gives users to the opportunity to look at the data themselves. More complicated components such as the map of each incident were left alone on a single page. US and state-level statistics were separated from one another. This short tutorial on how to create the dashboard and source code were included in the dashboard with programmers at all levels in mind. The goals of the dashboard and actionable information were each given separate pages from the output. 

For your dashboard, this may take as long as the output you would like to share took you to produce. 

### **5)** Add content to the dashboard.

You can begin adding content to the dashboard once you have an initial layout in mind. Keep in mind that this will likely be an iterative process. 

The `RMarkdown` file used to create a dashboard with `flexdashboard` works similarly to any other `RMarkdown`. There are some exceptions.

'''{r, echo = TRUE}
# This output was created with chunk options: {r, echo = TRUE}
paste("Code chunks can be explicitly included")
'''

'''{r}
# This output was created with chunk options: {r}
paste("Code chunks are hidden by default")
'''

Pages and columns within pages can be defined.

'''
Page
=========================================   

Column {data-width=500}
-------------------------------------

Column {data-width=500}
-------------------------------------
'''

As mentioned before, the `flexdashboard` metadata included in the `YAML` does also alter how `RMarkdown` functions. For more on how you can leverage both `RMarkdown` and `flexdashboard` to produce a dashboard, click [here](https://rmarkdown.rstudio.com/flexdashboard/index.html).

This [supplementary resource by the Open Case Studies project](INCLUDE LINK HERE) provides a case study on how to create this very dashboard in more detail.

Lastly, we create a Hotline page to spread awareness.

Hotline {data-icon="fa-exclamation-triangle"}
=========================================   

Column {data-width=600}
-------------------------------------

###

**Warning Signs**

From [Sandy Hook Promise](https://www.sandyhookpromise.org/gun-violence/know-the-signs-of-gun-violence/)...

avocado... there were some really interesting things here... but dont know where/if to include
https://www.sandyhookpromise.org/gun-violence/16-facts-about-gun-violence-and-school-shootings/

The most important seems to be that shooters usually warn someone

<style>
div.blue { background-color:#e6f0ff; border-radius: 5px; padding: 20px;}
</style>
<div class = "blue">

Here is a list of potential warning signs that can signal an individual may be in crisis and/or need help:

+ Suddenly withdrawing from people and activities
+ Consistent bullying or intimidating others, or being bullied by others
+ Extreme mood or personality changes
+ Victim of constant social rejection
+ Talking about plans or actively making plans to harm themselves or others
+ Bringing a weapon to school – or threatening or talking about doing so
+ Bragging about or warning others about an upcoming act of violence
+ Recruiting others to join in a planned act of violence
+ Warning students to stay away from school or events
+ Expressing fascination with guns and/or school shootings
+ Expressing hopelessness about the future
+ Extreme, prolonged sadness or distress
+ Expressing or showing feelings of isolation
+ Bragging about access to guns

**NOTE**

This list is not a comprehensive list of warning signs nor does exhibiting one of these signs indicate imminent violence.

When concerned about seeing troubling behaviors, tell a trusted adult or call 911, if there is an immediate threat.

</div>

Column {data-width=400}
-------------------------------------

### 

**Respond to Warning Signs**

Call 911 if you feel there is an immediate threat. 

Call [+1-844-5-SAYNOW](tel:18445729669) if you would to submit an anonymous safety concern.

Summary


Summary Plot

Synopsis

Suggested Homework


Create another dashboard with graphs and statistics featuring other elements within this dataset. For example, students may create graphs that explore what school events are reported to have more shootings.

Additional Information


Session Info

R version 4.0.1 (2020-06-06)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggforce_0.3.1       DT_0.14             lubridate_1.7.8    
 [4] htmltools_0.4.0     rmapshaper_0.4.4    leaflet_2.0.3      
 [7] forcats_0.5.0       stringr_1.4.0       purrr_0.3.4        
[10] tibble_3.0.1        tidyverse_1.3.0     shiny_1.4.0.2      
[13] flexdashboard_0.5.2 waffle_0.7.0        sf_0.9-3           
[16] ggmap_3.0.0         ggplot2_3.3.1       magrittr_1.5       
[19] tidyr_1.1.0         dplyr_1.0.0         readr_1.3.1        
[22] knitr_1.28          here_0.1           

loaded via a namespace (and not attached):
 [1] nlme_3.1-148        bitops_1.0-6        fs_1.4.1           
 [4] RColorBrewer_1.1-2  httr_1.4.1          rprojroot_1.3-2    
 [7] tools_4.0.1         backports_1.1.7     utf8_1.1.4         
[10] R6_2.4.1            KernSmooth_2.23-17  DBI_1.1.0          
[13] colorspace_1.4-1    withr_2.2.0         sp_1.4-2           
[16] tidyselect_1.1.0    gridExtra_2.3       curl_4.3           
[19] compiler_4.0.1      extrafontdb_1.0     cli_2.0.2          
[22] rvest_0.3.5         xml2_1.3.2          labeling_0.3       
[25] scales_1.1.1        classInt_0.4-3      digest_0.6.25      
[28] rmarkdown_2.2       base64enc_0.1-3     jpeg_0.1-8.1       
[31] pkgconfig_2.0.3     extrafont_0.17      dbplyr_1.4.4       
[34] fastmap_1.0.1       jsonvalidate_1.1.0  htmlwidgets_1.5.1  
[37] rlang_0.4.6         readxl_1.3.1        httpcode_0.3.0     
[40] rstudioapi_0.11     farver_2.0.3        generics_0.0.2     
[43] jsonlite_1.6.1      crosstalk_1.1.0.1   Rcpp_1.0.4.6       
[46] munsell_0.5.0       fansi_0.4.1         lifecycle_0.2.0    
[49] stringi_1.4.6       yaml_2.2.1          MASS_7.3-51.6      
[52] plyr_1.8.6          grid_4.0.1          blob_1.2.1         
[55] promises_1.1.1      crayon_1.3.4        lattice_0.20-41    
[58] haven_2.3.1         hms_0.5.3           pillar_1.4.4       
[61] rjson_0.2.20        geojsonlint_0.4.0   crul_1.0.0         
[64] reprex_0.3.0        glue_1.4.1          evaluate_0.14      
[67] V8_3.2.0            modelr_0.1.8        tweenr_1.0.1       
[70] png_0.1-7           vctrs_0.3.1         httpuv_1.5.4       
[73] RgoogleMaps_1.4.5.3 Rttf2pt1_1.3.8      cellranger_1.1.0   
[76] polyclip_1.10-0     gtable_0.3.0        assertthat_0.2.1   
[79] xfun_0.14           mime_0.9            xtable_1.8-4       
[82] broom_0.5.6         e1071_1.7-3         later_1.1.0.1      
[85] viridisLite_0.3.0   class_7.3-17        units_0.6-6        
[88] ellipsis_0.3.1     

Acknowledgements

We would like to acknowledge Elizabeth Stuart for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiAiRmlmdHkgWWVhcnMgb2YgU2Nob29sIFNob290aW5ncyBpbiB0aGUgVW5pdGVkIFN0YXRlcyIKY3NzOiBzdHlsZS5jc3MKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKCi0tLQoKPHN0eWxlPgojVE9DIHsKICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9pbWcvbG9nby5qcGciKTsKICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47CiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKfQo8L3N0eWxlPgoKCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgCjwhLS0gPGJhc2UgdGFyZ2V0PSJfYmxhbmsiLz4gICAtLT4KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAnOTAlJykKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGtuaXRyKQpgYGAKCiMjIyMgey5vdXRsaW5lIH0KYGBge3IsIGVjaG89RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoInNjcmVlbnNob3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZmluYWxfcGxvdC5wbmciKSkKYGBgCiMjIyMKCiMjIyMgey5kaXNjbGFpbWVyX2Jsb2NrfQoKKipEaXNjbGFpbWVyKio6IFRoZSBwdXJwb3NlIG9mIHRoZSBbT3BlbiBDYXNlIFN0dWRpZXNdKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pbyl7dGFyZ2V0PSJfYmxhbmsifSBwcm9qZWN0IGlzICoqdG8gZGVtb25zdHJhdGUgdGhlIHVzZSBvZiB2YXJpb3VzIGRhdGEgc2NpZW5jZSBtZXRob2RzLCB0b29scywgYW5kIHNvZnR3YXJlIGluIHRoZSBjb250ZXh0IG9mIG1lc3N5LCByZWFsLXdvcmxkIGRhdGEqKi4gQSBnaXZlbiBjYXNlIHN0dWR5IGRvZXMgbm90IGNvdmVyIGFsbCBhc3BlY3RzIG9mIHRoZSByZXNlYXJjaCBwcm9jZXNzLCBpcyBub3QgY2xhaW1pbmcgdG8gYmUgdGhlIG1vc3QgYXBwcm9wcmlhdGUgd2F5IHRvIGFuYWx5emUgYSBnaXZlbiBkYXRhIHNldCwgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBpbiB0aGUgY29udGV4dCBvZiBtYWtpbmcgcG9saWN5IGRlY2lzaW9ucyB3aXRob3V0IGV4dGVybmFsIGNvbnN1bHRhdGlvbiBmcm9tIHNjaWVudGlmaWMgZXhwZXJ0cy4gCgojIyMjCgojIyMjIHsubGljZW5zZV9ibG9ja30KClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsIDMuMCBbKENDIEJZLU5DIDMuMCldKGh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvdXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBVbml0ZWQgU3RhdGVzIExpY2Vuc2UuCgojIyMjCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKVG8gY2l0ZSB0aGlzIGNhc2Ugc3R1ZHkgcGxlYXNlIHVzZToKCldyaWdodCwgQ2FycmllLCBhbmQgT250aXZlcm9zLCBNaWNoYWVsIGFuZCBKYWdlciwgTGVhaCBhbmQgVGF1YiwgTWFyZ2FyZXQgYW5kIEhpY2tzLCBTdGVwaGFuaWUuICgyMDIwKS4gaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MteW91dGgtc2Nob29sLXNob290aW5ncy1kYXNoYm9hcmQtY2FzZS1zdHVkeS4gRmlmdHkgWWVhcnMgb2YgU2Nob29sIFNob290aW5ncyBpbiB0aGUgVW5pdGVkIFN0YXRlcyAoVmVyc2lvbiB2MS4wLjApLgoKIyMjIwoKIyMgKipNb3RpdmF0aW9uKioKKioqIAoKVGhpcyBjYXNlIHN0dWR5IGlzIG1vdGl2YXRlZCBieSB0aGlzIFthcnRpY2xlXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2NvbnRlbnQvcGRmLzEwLjEwMDcvczExOTIwLTAxMi0wMzMxLTYucGRmKToKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpGbGFubmVyeSwgRC4gSi4sIE1vZHplbGVza2ksIFcuICYgS3JldHNjaG1hciwgSi4gTS4gVmlvbGVuY2UgYW5kIFNjaG9vbCBTaG9vdGluZ3MuIEN1cnIgUHN5Y2hpYXRyeSBSZXAgMTUsIDMzMSAoMjAxMykuIERPSTogWzEwLjEwMDcvczExOTIwLTAxMi0wMzMxLTZdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3L3MxMTkyMC0wMTItMDMzMS02KQoKIyMjIwoKVGhpcyBhcnRpY2xlIGV4cGxvcmVzIGNoYXJhY3RlcmlzdGljcyBvZiBzY2hvb2wgc2hvb3RpbmdzIGFuZCB2aW9sZW5jZSBpbiBzY2hvb2xzIGFuZCBkaXNjdXNzZXMgd2h5IHRoZXNlIGV2ZW50cyBtYXkgb2NjdXIsIGFzIHdlbGwgYXMgdGhlaXIgaW1wYWN0IG9uIHRoZSBjb21tdW5pdGllcyBpbiB3aGljaCB0aGV5IG9jY3VyLgoKCgpUaGlzIGFydGljbGUgc3RhdGVzIHRoYXQgdGhlIHNob290ZXJzIG9mIG1vc3QgY29tbW9ubHkgd2hpdGUgbWFsZXMsIGJ1dCB0aGF0IG1hbnkgcHJldmlvdXMgc3R1ZGllcyBvZiBzaG9vdGVyIGNoYXJhY3RlcmlzaXRjcyBjb3VsZCBub3QgaWRlbnRpZnkgYW55IHBhcnRpY3VsYXIgInByb2ZpbGUiIG9mIHNob290ZXJzLgoKPiAiVG8gZGF0ZSwgc3R1ZGllcyBvZiBzY2hvb2wgc2hvb3RpbmdzIGhhdmUgY29uY2x1ZGVkIHRoYXQgbm8KY29uc2lzdGVudCBhbmQgcmVsaWFibGUgcHJvZmlsZSBvZiBzY2hvb2wgc2hvb3RlcnMgZXhpc3QsIGFuZAptb3N0IHJlc2VhcmNoZXJzIGFuZCBjbGluaWNpYW5zIHdvdWxkIGFncmVlIHRoYXQgcHJlZGljdGluZwp2aW9sZW50IGJlaGF2aW9yIGlzIGEgc2xpcHBlcnkgc2xvcGUgdGhhdCB3aWxsIHVzdWFsbHkgcmVzdWx0IGluCm1vcmUgZmFsc2UgcG9zaXRpdmVzIHRoYW4gZmFsc2UgbmVnYXRpdmVzLiIKCkhvd2V2ZXIgcHJldmlvdXMgc3R1ZGllcyBub3RlIHNvbWUgY29tbW9uYWxpdGVzIHN1Y2ggYXM6Cgo+ICIuLi5tb3N0IHNob290ZXJzIHdlcmUgZGVwcmVzc2VkLCBoYWQgZXhwZXJpZW5jZWQgc29tZSBzaWduaWZpY2FudApsb3NzLCBmZWx0IHBlcnNlY3V0ZWQgb3IgYnVsbGllZCBieSBvdGhlcnMsIGFuZCBoYWQgcHJpb3IKZGlmZmljdWx0eSBjb3Bpbmcgb3IgaGFkIHByZXZpb3VzbHkgdHJpZWQgc3VpY2lkZS4gTW9zdCBvZgp0aGUgc2hvb3RlcnMgZGlkIG5vdCwgaG93ZXZlciwgaGF2ZSBhIGhpc3Rvcnkgb2YgZHJ1ZyBhYnVzZQpvciB2aW9sZW5jZSBvciBjcnVlbHR5IHRvIGFuaW1hbHMsIGNvbW1vbiBwc3ljaGlhdHJpYyBpbmRpY2F0b3JzIG9mIHJpc2ssIG5vciBkaWQgdGhleSByZXBvcnQgZXhjZXNzaXZlIGV4cG9zdXJlIHRvCnZpb2xlbmNlIGluIHRoZSBtZWRpYSAodGhvdWdoIG1hbnkgcHJvZHVjZWQgdGhlaXIgb3duCnZpb2xlbnQgdGhlbWVzIGluIHdyaXRpbmdzIG9yIGRyYXdpbmdzKS4iCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImpvc2h1YS1ob2VobmUtQ0Fva2d4MUdHS0UtdW5zcGxhc2guanBnIikpCmBgYAoKCjxzcGFuPlBob3RvIGJ5IDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL0BtcnRoZXRyYWluP3V0bV9zb3VyY2U9dW5zcGxhc2gmYW1wO3V0bV9tZWRpdW09cmVmZXJyYWwmYW1wO3V0bV9jb250ZW50PWNyZWRpdENvcHlUZXh0Ij5Kb3NodWEgSG9laG5lPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3Vuc3BsYXNoLmNvbS9zL3Bob3Rvcy9oaWdoLXNjaG9vbD91dG1fc291cmNlPXVuc3BsYXNoJmFtcDt1dG1fbWVkaXVtPXJlZmVycmFsJmFtcDt1dG1fY29udGVudD1jcmVkaXRDb3B5VGV4dCI+VW5zcGxhc2g8L2E+PC9zcGFuPgoKCgo+ICJTY2hvb2wgc2hvb3RpbmdzIGFyZSBub3QgYWxsIHRoZSBzYW1lIGFuZCBtYXkgcmVxdWlyZQpkaWZmZXJlbnQgYXBwcm9hY2hlcyB0byBwcmV2ZW50aW9uIGFuZCB0cmVhdG1lbnQsIGVzcGVjaWFsbHkKd2l0aCByZXNwZWN0IHRvIGlkZW50aWZ5aW5nIHJpc2sgZmFjdG9ycyBhdCB0aGUgaW5kaXZpZHVhbCwgc2Nob29sCm9yIGNvbW11bml0eSBsZXZlbHMsIGFuZCBwYXJ0aWN1bGFybHkgd2l0aCByZWdhcmQgdG8gZXhhbWluaW5nCnRoZSByb2xlIHRoYXQgbWVudGFsIGhlYWx0aCBpc3N1ZXMgbWF5IHBsYXkgdG8gaW5jcmVhc2UgcmlzayBmb3IKcGVycGV0cmF0aW9uLiBUaGUgZmllbGQgKipuZWVkcyB0byBrbm93IG1vcmUqKiBhYm91dCBzaG9vdGluZwppbmNpZGVudHMgdGhhdCBhcmUgYXZlcnRlZCwgdGhvc2UgdGhhdCByZXN1bHQgaW4gaW5qdXJ5IGJ1dCBub3QKZGVhdGggYW5kIGFib3V0IHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIG1vcmUgY29tbW9uIG9jY3VycmVuY2Ugb2Ygc2luZ2xlIGhvbWljaWRlIHNjaG9vbCBzaG9vdGluZ3MuIgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJhbmRyZS1odW50ZXItQVE5MDhGZmRBTXctdW5zcGxhc2guanBnIikpCmBgYAoKPHNwYW4+UGhvdG8gYnkgPGEgaHJlZj0iaHR0cHM6Ly91bnNwbGFzaC5jb20vQGRyZTAzMTY/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPkFuZHJlIEh1bnRlcjwvYT4gb24gPGEgaHJlZj0iaHR0cHM6Ly91bnNwbGFzaC5jb20vcy9waG90b3MvaGlnaC1zY2hvb2w/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4KCgpUaGV5IGFsc28gcG9pbnQgb3V0IHRoYXQ6Cgo+ICJNb3N0IG1lZGlhIGF0dGVudGlvbiBpcyBvbiB0aGUgbWVudGFsIGhlYWx0aCBvZiBzY2hvb2wgc2hvb3RlcnMsIGJ1dCB3ZSBjYW5ub3QgZm9yZ2V0IHRoZSAqKmltcGFjdCBvZiBzY2hvb2wgc2hvb3RpbmcgaW5jaWRlbnRzIG9uIHRoZSBzdXJ2aXZpbmcgdmljdGltcyoqLCBpbmNsdWRpbmcgdGhvc2Ugd2hvIG1heSBub3QgaGF2ZSBiZWVuIGluanVyZWQgYnV0IHdobyBtYXkgaGF2ZSB3aXRuZXNzZWQgdGhlIGluY2lkZW50IG9yIGJlZW4gYWZmZWN0ZWQgYnkgaXQgaW4gb3RoZXIgd2F5cy4gUHN5Y2hpYXRyaXN0cyBtdXN0IHBheSBhdHRlbnRpb24gdG8gdGhlIGxvbmctdGVybSBtZW50YWwgaGVhbHRoIGNvbnNlcXVlbmNlcyBvZiB0aGVzZSBpbmNpZGVudHMgb24gYWxsIGFmZmVjdGVkIHBhcnRpZXMgKG5vdCBqdXN0IGZvcm1hbCBQVFNEIGRpYWdub3NlcywgYnV0IHJlbGF0ZWQgdHJhdW1hIHN5bXB0b21zKSBhcyB3ZWxsIGFzIG1hbGFkYXB0aXZlIGNvcGluZyBzdHJhdGVnaWVzIHRoYXQgc29tZSBtYXkgZW1wbG95IGluIHJlc3BvbnNlIHRvIHN1Y2ggdW5wcmVkaWN0YWJsZSwgdHJhZ2ljIGV2ZW50cy4iCgpHaXZlbiB0aGlzIG5lZWQgZm9yIG1vcmUgcmVzZWFyY2ggdG8gYmV0dGVyIHVuZGVyc3RhbmQgd2h5IHRoZXNlIGV2ZW50cyBvY2N1ciBhbmQgaG93IHRoZXkgY291bGQgYmUgYXZlcnRlZCwgaW4gdGhpcyBjYXNlIHN0dWR5IHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvIGNyZWF0ZSBhIHJlc291cmNlIGZvciBvdGhlcnMgdG8gbW9yZSBlYXNpbHkgYW5kIGludGVyYWN0aXZlbHkgYWNjZXNzIGRhdGEgYWJvdXQgc2Nob29sIHNob290aW5ncy4gVG8gZG8gc28gd2Ugd2lsbCBjcmVhdGUgd2hhdCBpcyBjYWxsZWQgYSBbZGFzaGJvYXJkXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EYXNoYm9hcmRfKGJ1c2luZXNzKSksIHdoaWNoIGlzIGEgd2Vic2l0ZSB0aGF0IGRpc3BsYXlzIGEgcmVwb3J0IGZvciBhIGRhdGFiYXNlLiBEYXNoYm9hcmRzIHN1bW1hcml6ZSB0aGUgZGF0YSBpbiBhIGRhdGFiYXNlIGFuZCB0eXBpY2FsbHkgYWxsb3cgZm9yIHVzZXJzIHRvIGludGVyYWN0IHdpdGggdGhlIGRhdGEgaW4gc29tZSB3YXkuCgoKIyMgKipNYWluIFF1ZXN0aW9ucyoqCioqKiAKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb25zOiA8L3U+PC9iPgoKMSkgV2hhdCBoYXMgYmVlbiB0aGUgeWVhcmx5IHJhdGUgb2Ygc2Nob29sIHNob290aW5ncyBhbmQgd2hlcmUgaGF2ZSB0aGV5IG9jY3VycmVkIGluIHRoZSBsYXN0IDUwIHllYXJzIChmcm9tIEphbnVhcnkgMTk3MCB0byBKdW5lIDIwMjApPyAKCjIpIFdoYXQgYXJlIHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlc2UgZXZlbnRzPwoKIyMjIwoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKiogCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBkZW1vbnN0cmF0ZSBob3cgdG8gY3JlYXRlIGEgW2Rhc2hib2FyZF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRGFzaGJvYXJkXyhidXNpbmVzcykpLCB3aGljaCBpcyBhIHdlYnNpdGUgdGhhdCBkaXNwbGF5cyBhIHJlcG9ydCBhYm91dCBhIGRhdGFiYXNlLiBXZSB3aWxsIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYFRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9LCBzdWNoIGFzIGBwYWNrYWdlX25hbWVgLCBgcGFja2FnZV9uYW1lYC4gVGhlIHRpZHl2ZXJzZSBpcyBhIGxpYnJhcnkgb2YgcGFja2FnZXMgY3JlYXRlZCBieSBSU3R1ZGlvLiBXaGlsZSBzb21lIHN0dWRlbnRzIG1heSBiZSBmYW1pbGlhciB3aXRoIHByZXZpb3VzIFIgcHJvZ3JhbW1pbmcgcGFja2FnZXMsIHRoZXNlIHBhY2thZ2VzIG1ha2UgZGF0YSBzY2llbmNlIGluIFIgbW9yZSBsZWdpYmxlIGFuZCBpbnR1aXRpdmUuCgoKYGBge3IsIG91dC53aWR0aCA9ICIyMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9CmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vdGlkeXZlcnNlLnRpZHl2ZXJzZS5vcmcvbG9nby5wbmciKQpgYGAKClRoZSBza2lsbHMsIG1ldGhvZHMsIGFuZCBjb25jZXB0cyB0aGF0IHN0dWRlbnRzIHdpbGwgYmUgZmFtaWxpYXIgd2l0aCBieSB0aGUgZW5kIG9mIHRoaXMgY2FzZSBzdHVkeSBhcmU6CgpBdm9jYWRvIHVwZGF0ZSBoZXJlIGFuZCBpbiByZWFkbWUhCgpEYXRhIHNjaWVuY2Ugc2tpbGxzOiAgCgoxLiBJbXBvcnRpbmcgdGV4dCBmcm9tIGEgZ29vZ2xlIHNoZWV0cyBkb2N1bWVudD8/PwoyLiBBcHBseSBhY3Rpb24gdmVyYnMgaW4gYGRwbHlyYCBmb3IgZGF0YSB3cmFuZ2xpbmcgIAozLiBIb3cgdG8gcmVzaGFwZSBkYXRhIGJ5IHBpdm90aW5nIGJldHdlZW4gImxvbmciIGFuZCAid2lkZSIgZm9ybWF0cyBhbmQgc2VwYXJhdGluZyBjb2x1bW5zIGludG8gYWRkaXRpb25hbCBjb2x1bW5zIChgdGlkeXJgKSAgCjQuIEhvdyB0byBmaWxsIGluIGRhdGEgYmFzZWQgb24gcHJldmlvdXMgdmFsdWVzIChgdGlkeXJgKQo1LiBIb3cgdG8gY3JlYXRlIGRhdGEgdmlzdWFsaXphdGlvbnMgd2l0aCBgZ2dwbG90MmAgdGhhdCBhcmUgaW4gYSBzaW1pbGFyIHN0eWxlIHRvIGFuIGV4aXN0aW5nIGltYWdlICAgIAo2LiBIb3cgdG8gYWRkIGltYWdlcyB0byBwbG90cyB1c2luZyBgY293cGxvdGAKNy4gSG93IHRvIGNyZWF0ZSBlZmZlY3RpdmUgYmFyIHBsb3RzIHRvIGZvciBtdWx0aXBsZSBjb21wYXJpc29ucywgaW5jbHVkaW5nIGFkZGluZyBnYXBzIGJldHdlZW4gYmFycyBpbiBiYXIgcGxvdHMsIGFkZGluZyBmaWd1cmUgbGVnZW5kcyB0byB0aGUgcGxvdCBhcmVhLCBhbmQgYWRkaW5nIGNvbXBhcmlzb24gbGluZXMgKGBnZ3Bsb3QyYCkKClN0YXRpc3RpY2FsIGNvbmNlcHRzIGFuZCBtZXRob2RzOiAgCgoKKioqIAoKCldlIHdpbGwgYmVnaW4gYnkgbG9hZGluZyB0aGUgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5lZWQ6CgoKYGBge3J9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShnZ21hcCkKbGlicmFyeShzZikKbGlicmFyeSh3YWZmbGUpCmxpYnJhcnkoZmxleGRhc2hib2FyZCkKbGlicmFyeShzaGlueSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobGVhZmxldCkKCmxpYnJhcnkocm1hcHNoYXBlcikKbGlicmFyeShodG1sdG9vbHMpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KERUKQpgYGAKCgogPHU+KipQYWNrYWdlcyB1c2VkIGluIHRoaXMgY2FzZSBzdHVkeToqKiA8L3U+CgpQYWNrYWdlICAgfCBVc2UgaW4gdGhpcyBjYXNlIHN0dWR5ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhICAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKSB8ICB0byBpbXBvcnQgdGhlIGRhdGEgICAgCltkcGx5cl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gZmlsdGVyLCBzdWJzZXQsIGpvaW4sIGFkZCByb3dzIHRvLCBhbmQgbW9kaWZ5IHRoZSBkYXRhICAgIApbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5pcHVsYXRlICBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEKW21hZ3JpdHRyXShodHRwczovL21hZ3JpdHRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBwaXBlIHNlcXVlbnRpYWwgY29tbWFuZHMgCltnZ21hcF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dnbWFwL2dnbWFwLnBkZikgfCB0byBnZW9jb2RlIHRoZSBkYXRhICh3aGljaCBtZWFucyBnZXQgdGhlIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgdmFsdWVzIGZvciB0aGUgc2Nob29scykKW3dhZmZsZV0oaHR0cHM6Ly9naXRodWIuY29tL2hyYnJtc3RyL3dhZmZsZSkgfCB0byBtYWtlIHdhZmZsZSBwcm9wb3J0aW9uIHBsb3QKW2ZsZXhkYXNoYm9hcmRdKGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2ZsZXhkYXNoYm9hcmQvKSAgICAgfCB0byBjcmVhdGUgdGhlIGVsZW1lbnRzIG9mIHRoZSBkYXNoYm9hcmQgCgpbdGlkeXJdKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGNoYW5nZSB0aGUgc2hhcGUgb3IgZm9ybWF0IG9mIHRpYmJsZXMgdG8gd2lkZSBhbmQgbG9uZywgdG8gZHJvcCByb3dzIHdpdGggYE5BYCB2YWx1ZXMsIHRvIHNlcGFyYXRlIGEgY29sdW1uIGludG8gYWRkaXRpb25hbCBjb2x1bW5zLCBhbmQgdG8gZmlsbCBvdXQgdmFsdWVzIGJhc2VkIG9uIHByZXZpb3VzIHZhbHVlcyAgIApbc2hpbnldKGh0dHBzOi8vc2hpbnkucnN0dWRpby5jb20vZ2FsbGVyeS8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGF2b2NhZG8gIApbbGVhZmxldF0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFmbGV0L3NoaW55Lmh0bWwpIHwgdG8gaW1wbGVtZW50IHRoZSBjcmVhdGUgdGhlIG1hcCBmb3Igb3VyIGRhc2hib2FyZCAgIApbc2ZdKGh0dHBzOi8vci1zcGF0aWFsLmdpdGh1Yi5pby9zZi8pIHwgdG8gR2VvY29kZSB0aGUgZGF0YSBhdm9jYWRvCltybWFwc2hhcHBlcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3JtYXBzaGFwZXIvdmlnbmV0dGVzL3JtYXBzaGFwZXIuaHRtbCkgfCBhdm9jYWRvCltodG1sdG9vbHNdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9odG1sdG9vbHMvdmVyc2lvbnMvMC41LjApIHwgdG8gYXZvY2FkbyAgIApbbHVicmlkYXRlXShodHRwczovL2x1YnJpZGF0ZS50aWR5dmVyc2Uub3JnLykgfCB0byB3b3JrIHdpdGggdGhlIGRhdGEtdGltZSBkYXRhICAgIApbRFRdKGh0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vRFQvKSB8IHRvIGNyZWF0ZSB0aGUgaW50ZXJhY3RpdmUgdGFibGUgIApbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjcmVhdGUgcGxvdHMgIApbZGlyZWN0bGFiZWxzXShodHRwOi8vZGlyZWN0bGFiZWxzLnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9kb2NzL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFkZCBsYWJlbHMgZGlyZWN0bHkgdG8gbGluZXMgaW4gcGxvdHMgIApbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBhZGQgaW1hZ2VzIHRvIHBsb3RzIApbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZW9yZGVyIGZhY3RvciBmb3IgcGxvdAoKW3BhdGNod29ya10oaHR0cHM6Ly9naXRodWIuY29tL3Rob21hc3A4NS9wYXRjaHdvcmspIHwgdG8gY29tYmluZSBwbG90cwoKCgpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojIyAqKkNvbnRleHQqKgoqKiogCgpBbHRob3VnaCBzY2hvb2wgc2hvb3RpbmcgZXZlbnRzIHRoYXQgcmVzdWx0IGluIGhvbWljaWRlIGFyZSByYXJlLCB0aGV5IGNhbiBoYXZlIGEgbGFzdGluZyBpbXBhY3Qgb24gdGhlIGNvbW11bml0aWVzIGluIHdoaWNoIHRoZXkgb2NjdXIuIEZ1cnRoZXJtb3JlLCBzdWljaWRlIGV2ZW50cyBhbmQgc2hvb3RpbmdzIHdpdGggbm8gdmljdGltcyBjYW4gYWxzbyBiZSBpbXBhY3RmdWwuCgpBY2NvcmRpbmcgdG8gdGhlIFtDZW50ZXIgZm9yIEluanVyeSBSZXNlYXJjaCBhbmQgUHJldmVudGlvbiBhdCB0aGUgQ2hpbGRyZW4ncyBIb3NwaXRhbCBvZiBQaGlsYWRlbHBoaWFdKGh0dHBzOi8vaW5qdXJ5LnJlc2VhcmNoLmNob3AuZWR1L3Zpb2xlbmNlLXByZXZlbnRpb24taW5pdGlhdGl2ZS90eXBlcy12aW9sZW5jZS1pbnZvbHZpbmcteW91dGgvc2Nob29sLXNob290aW5ncyk6Cgo+VGhlIG1vc3QgY29tbW9uIHNob290aW5ncyBvbiBzY2hvb2wgZ3JvdW5kcyByYXJlbHkgaW52b2x2ZSBsYXJnZSBudW1iZXJzIG9mIHZpY3RpbXMsIGJ1dCBldmVuIGEgc2hvb3Rpbmcgb2YganVzdCBvbmUgc3R1ZGVudCBhdCBzY2hvb2wgaGFzIHJhbWlmaWNhdGlvbnMgZmFyIGJleW9uZCB0aG9zZSBkaXJlY3RseSBpbnZvbHZlZC4gU3R1ZGVudHMgYW5kIHN0YWZmIHRoYXQgd2l0bmVzcyBzY2hvb2wgc2hvb3RpbmdzIGFyZSBsaWtlbHkgdG8gc3VmZmVyIGZyb20gW3RyYXVtYXRpYyBzdHJlc3NdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1RyYXVtYXRpY19zdHJlc3MpIHN5bXB0b21zLCBiZWNvbWUgYW54aW91cyBvciBkZXByZXNzZWQgYW5kIGhhdmUgZ2VuZXJhbCBjb25jZXJucyBhYm91dCB0aGVpciBzYWZldHkuIFdoaWxlIG1hbnkgd2l0bmVzc2VzIHdpbGwgaGF2ZSB0ZW1wb3Jhcnkgc3ltcHRvbXMsIG90aGVycyB3aWxsIGJlIHN5bXB0b21hdGljIGZvciBhIG11Y2ggbG9uZ2VyIHBlcmlvZCBvZiB0aW1lIGFuZCBldmVuIGRldmVsb3AgY2hyb25pYyBwc3ljaGlhdHJpYyBkaXNvcmRlcnMuIEV2ZW4gc2hvcnQtdGVybSBpbXBhaXJtZW50cyBjYW4gY2F1c2Ugc2V2ZXJlIGRpc3RyZXNzIGFuZCBoYXZlIHByb2ZvdW5kIGVmZmVjdHMgb24gYWNhZGVtaWMgYWNoaWV2ZW1lbnQgYW5kIHRoZSBzb2NpYWwgYW5kIGVtb3Rpb25hbCBncm93dGggb2YgaW1wYWN0ZWQgc3R1ZGVudHMuIAogCkZ1cnRoZXJtb3JlLCBmYXRhbCBzaG9vdGluZ3MgY2FuIGhhdmUgdmFzdCBhbmQgbGFzdGluZyBpbXBhY3RzIGJlY2F1c2UgbWFueSBzdHVkZW50cyBjYW4gd2l0bmVzcyBhIHNpbmdsZSBldmVudC4KCkFub3RoZXIgcmVjZW50bHkgcHVibGlzaGVkIFthcnRpY2xlXShodHRwczovL3NpZXByLnN0YW5mb3JkLmVkdS9zaXRlcy9kZWZhdWx0L2ZpbGVzL3B1YmxpY2F0aW9ucy8xOS0wMzYucGRmKSBpbmRpY2F0ZXMgdGhhdDoKCj4gT3ZlciAqKjI0MCwwMDAqKiBBbWVyaWNhbiBzdHVkZW50cyBleHBlcmllbmNlZCBhIHNjaG9vbCBzaG9vdGluZyBpbiB0aGUgbGFzdCB0d28gZGVjYWRlcy4KCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImV4cG9zZWQucG5nIikpCgpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9zaWVwci5zdGFuZm9yZC5lZHUvc2l0ZXMvZGVmYXVsdC9maWxlcy9wdWJsaWNhdGlvbnMvMTktMDM2LnBkZikKIApUaGlzIHN0dWR5IGZvbGxvd2VkIHN0dWRlbnRzIHdobyBleHBlcmllbmNlZCBhIHNjaG9vbCBzaG9vdHRpbmcgdGhlIFVuaXRlZCBTdGF0ZXMgYmV0d2VlbiAyMDA4IGFuZCAyMDEzIGFuZCBhc3Nlc3NlZCB0aGVpciBtZW50YWwgd2VsbC1iZWluZy4gVGhleSBmb3VuZCB0aGF0OgoKPiBGYXRhbCBzY2hvb2wgc2hvb3RpbmdzIGhhdmUgbGFyZ2UgYW5kIHBlcnNpc3RlbnQgaW1wYWN0cyBvbiB0aGUgbWVudGFsIGhlYWx0aCBvZiBsb2NhbCB5b3V0aC4gSW4gdGhlIHR3byB5ZWFycyBmb2xsb3dpbmcgYSBmYXRhbCBzY2hvb2wgc2hvb3RpbmcsIHRoZSBtb250aGx5IG51bWJlciBvZiBhbnRpZGVwcmVzc2FudCBwcmVzY3JpcHRpb25zIHdyaXR0ZW4gdG8gaW5kaXZpZHVhbHMgdW5kZXIgYWdlIDIwIGlzIDIxLjMgcGVyY2VudCBoaWdoZXIgaW4gdGhlIHNob290aW5nLWV4cG9zZWQgcmVsYXRpdmUgdG8gdGhlIHJlZmVyZW5jZSBhcmVhcy4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXR3aWR0aCA9ICI0MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZmVybmFuZG8tY2ZlcmRvLTZ4MmlLR2k2U1BVLXVuc3BsYXNoLmpwZyIpKQpgYGAKCjxzcGFuPlBob3RvIGJ5IDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL0BjZmVyZG8/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPkZlcm5hbmRvIEBjZmVyZG88L2E+IG9uIDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL3MvcGhvdG9zL2RlcHJlc3Npb24/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4KCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKUm9zc2luLVNsYXRlciwgTS4sIFNjaG5lbGwsIE0uLCBTY2h3YW5kdCwgSC4sIFRyZWpvLCBTLiAmIFVuaWF0LCBMLiBMb2NhbCBFeHBvc3VyZSB0byBTY2hvb2wgU2hvb3RpbmdzIGFuZCBZb3V0aCBBbnRpZGVwcmVzc2FudCBVc2UuIHcyNjU2MyBodHRwOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjY1NjMucGRmICgyMDE5KSBkb2k6MTAuMzM4Ni93MjY1NjMuCgojIyMjCiAKIyMgKipMaW1pdGF0aW9ucyoqCioqKiAKVGhlcmUgYXJlIHNvbWUgaW1wb3J0YW50IGNvbnNpZGVyYXRpb25zIHJlZ2FyZGluZyB0aGlzIGRhdGEgYW5hbHlzaXMgdG8ga2VlcCBpbiBtaW5kOiAKCjEpIFRoaXMgYW5hbHlzaXMgaXMgZXhwbG9yYXRvcnkgYW5kLCBhcyBzdWNoLCBkb2VzIG5vdCBpbnRlbmQgdG8gcHJvdmlkZSBpbmZlcmVudGlhbCBjb25sY3VzaW9ucy4gIAoKMikgVGhpcyBkYXNoYm9hcmQgb25seSB1c2VzIG9uZSBzb3VyY2Ugb2YgZGF0YS4gVGhlcmUgbWF5IGJlIHNjaG9vbCBzaG9vdGluZyBldmVudHMgdGhhdCBhcmUgbm90IGxpc3RlZCBpbiB0aGlzIGRhdGEgb3IgZXJyb3JzIGluIHRoaXMgZGF0YS4KCkFjY29yZGluZyB0byB0aGUgZGF0YWJhc2Ugd2Vic2l0ZToKCj4iVGhpcyBkYXRhYmFzZSB3YXMgZGV2ZWxvcGVkIGZyb20gb3Blbi1zb3VyY2UgaW5mb3JtYXRpb24gYW5kIG1heSBpbmNsdWRlIHJlcG9ydGluZyBlcnJvcnMuIgoKRnVydGhlcm1vcmUsIGFjY29yZGluZyB0byB0aGlzIFthcnRpY2xlXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2FydGljbGUvMTAuMTAwNy9zMTE5MjAtMDEyLTAzMzEtNikgc2Nob29scyBhcmUgbm90IHJlcXVpcmVkIHRvIHJlcG9ydCBzY2hvb2wgc2hvb3RpbmdzIHVubGVzcyB0aGV5IHJlc3VsdGVkIGluIGEgc3VpY2lkZSBvciBob21pY2lkZSwgdGhlcmVmb3JlIHRoZXJlIG1heSBiZSBtb3JlIGV2ZW50cyB0aGF0IHJlc3VsdCBpbiBvbmx5IGluanVyeSBvciBubyBpbmp1cmllcyBvciBkZWF0aCB0aGF0IG1heSBub3QgYmUgaW5jbHVkZWQuCgpUaGVyZSBhcmUgaW5kZWVkIGV2ZW50cyBpbiB0aGUgZGF0YXNldCB0aGF0IGluY2x1ZGUgemVybyBkZWF0aHMgYW5kIHplcm8gaW5qdXJpZXMsIGJ1dCBpdCBpcyB2ZXJ5IGxpa2VseSB0aGF0IG1hbnkgb2YgdGhlc2UgZXZlbnRzIGFyZSBub3QgbGlzdGVkLgoKQXZvY2Fkby4uLiB0aGlzIHNvdXJjZSBmcm9tIDIwMTMgc2F5cyB0aGF0IHNjaG9vbHMgYXJlIG5vdCByZXF1aXJlZCB0byByZXBvcnQuLiBpcyB0aGlzIHN0aWxsIHRydWU/CgoKIyMgKipXaGF0IGFyZSB0aGUgZGF0YT8qKgoqKiogCgpXZSB3aWxsIHVzZSBkYXRhIGZyb20gdGhlIG9wZW4tc291cmNlIFtLLTEyIFNob29sU2hvb3RpbmcgRGF0YWJhc2VdKGh0dHBzOi8vd3d3LmNoZHMudXMvc3NkYi9kYXRhc2V0LykgZG93bmxvYWRlZCBmcm9tIHRoZSBbQ2VudGVyIGZvciBIb21lbGFuZCBEZWZlbnNlIGFuZCBTZWN1cml0eV0oaHR0cHM6Ly93d3cuY2hkcy51cy9jLykgYXQgdGhlIGF0IHRoZSBbTmF2YWwgUG9zdGdyYWR1YXRlIFNjaG9vbChOUFMpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9OYXZhbF9Qb3N0Z3JhZHVhdGVfU2Nob29sKSBpbiBNb250ZXJleSwgQ2FsaWZvcm5pYS4gVGhpcyBkYXRhIGlzIHVwZGF0ZWQgZGFpbHkuIAoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KClJpZWRtYW4sIERhdmlkLCBhbmQgRGVzbW9uZCBP4oCZTmVpbGwuIOKAnENIRFMg4oCTIEstMTIgU2Nob29sIFNob290aW5nIERhdGFiYXNlLuKAnSBDZW50ZXIgZm9yIEhvbWVsYW5kIERlZmVuc2UgYW5kIFNlY3VyaXR5LCBKdW5lIDIwMjAsIFt3d3cuY2hkcy51cy9zc2RiXSh3d3cuY2hkcy51cy9zc2RiKS4KCiMjIyMKClRoaXMgZGF0YWJhc2UgaW5jbHVkZXMgaW5mb3JtYXRpb24gYWJvdXQgc2Nob29sIHNob290aW5nIGV2ZW50cyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBkYXRpbmcgYmFjayB0byAxOTcwLiBUaGUgZGF0YWJhc2UgaGFzIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gbm90IHNob3duIG9uIG91ciBkYXNoYm9hcmQgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzogCgotIExvY2F0aW9uIG9mIHRoZSBldmVudCBhdCB0aGUgc2Nob29sICAKLSBJZiB0aGUgZXZlbnQgb2NjdXJlZCBkdXJpbmcgYSBzcG9ydGluZyBldmVudCAgCi0gVGltZSBvZiBkYXkgb2YgdGhlIGV2ZW50ICAKLSBEYXkgb2YgdGhlIHdlZWsgb2YgdGhlIGV2ZW50ICAKLSBzb3VyY2UgZm9yIHRoZSBzaG9vdGluZyBpbmZvcm1hdGlvbiAgCi0gSWYgdGhlIGV2ZW50IHdhcyBwcmUtcGxhbm5lZCBvciBub3QgIAotIFNob290ZXIncyBhY3Rpb25zIGltbWVkaWF0ZWx5IGZvbGxvd2luZyB0aGUgc2hvb3RpbmcgIAotIFNob290ZXIgY2hhcmFjdGVyaXN0aWNzIChhZmZpbGlhdGlvbiB3aXRoIHRoZSBzY2hvb2wsIGlmIHRoZXkgaGFkIGFjY29tcGxpY2VzLCBpZiB0aGV5IHRvb2sgaG9zdGFnZXMsIGFuZCB0aGVpciBhZ2UgYW5kIHJhY2UpICAKLSB2aWN0b20gY2hhcmFjdGVyaXN0aWNzKGFmZmljbGlhdGlvbiB3aXRoIHRoZSBzY2hvb2wsIGlmIHRoZXkgd2VyZSB0YXJnZXRlZCwgdGhlaXIgYWdlIGFuZCByYWNlKSAgCgpBY2NvcmRpbmcgdG8gdGhlIGRhdGEgYmFzZSB3ZWJzaXRlOgoKPiBUaGUgU2Nob29sIFNob290aW5nIERhdGFiYXNlIFByb2plY3QgaXMgY29uZHVjdGVkIGFzIHBhcnQgb2YgdGhlIFtBZHZhbmNlZCBUaGlua2luZyBpbiBIb21lbGFuZCBTZWN1cml0eSAoSFN4KV0oaHR0cHM6Ly93d3cuY2hkcy51cy9jL2FjYWRlbWljLXByb2dyYW1zL2hzeC8pIHByb2dyYW0gYXQgdGhlIE5hdmFsIFBvc3RncmFkdWF0ZSBTY2hvb2zigJlzIFtDZW50ZXIgZm9yIEhvbWVsYW5kIERlZmVuc2UgYW5kIFNlY3VyaXR5IChDSERTKV0oQ2VudGVyIGZvciBIb21lbGFuZCBEZWZlbnNlIGFuZCBTZWN1cml0eSAoQ0hEUykuCgo+VGhlIGRhdGFiYXNlIGNvbXBpbGVzIGluZm9ybWF0aW9uIGZyb20gbW9yZSB0aGFuIDI1IGRpZmZlcmVudCBzb3VyY2VzIGluY2x1ZGluZyBwZWVyLXJldmlld2VkIHN0dWRpZXMsIGdvdmVybm1lbnQgcmVwb3J0cywgbWFpbnN0cmVhbSBtZWRpYSwgbm9uLXByb2ZpdHMsIHByaXZhdGUgd2Vic2l0ZXMsIGJsb2dzLCBhbmQgY3Jvd2Qtc291cmNlZCBsaXN0cyB0aGF0IGhhdmUgYmVlbiBhbmFseXplZCwgZmlsdGVyZWQsIGRlY29uZmxpY3RlZCwgYW5kIGNyb3NzLXJlZmVyZW5jZWQuIEFsbCBvZiB0aGUgaW5mb3JtYXRpb24gaXMgYmFzZWQgb24gb3Blbi1zb3VyY2UgaW5mb3JtYXRpb24gYW5kIDNyZCBwYXJ0eSByZXBvcnRpbmcuCgojIyAqKkRhdGEgSW1wb3J0KioKKioqIAoKVG8gaW1wb3J0IHRoZSByYXcgZGF0YSBmaWxlIHdlIHdpbGwgdXNlIHRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWFkcmAgcGFja2FnZS4gCgpXZSB3aWxsIHVzZSB0aGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlIHRvIGVhc2lseSBsb2NhdGUgdGhlIGRhdGEgd2l0aGluIHRoZSBgcmF3X2RhdGFgIGRpcmVjdG9yeSB3aXRoaW4gdGhlIGRpcmVjdG9yeSB0aGF0IGNvbnRhaW5zIHRoZSAuUnByb2ogZmlsZS4KCldlIHdhbnQgdG8gc2tpcCB0aGUgZmlyc3Qgcm93IHRoYXQgc3RhdGVzOgpVcGRhdGVkIDYvMi8yMDIwIC0gVmlldyBncmFwaHMgYW5kIHJlc2VhcmNoIG1ldGhvZG9sb2d5IG9uIHd3dy5jaGRzLnVzL3NzZGIgSWYgeW91IGhhdmUgaW5mb3JtYXRpb24gYWJvdXQgb3RoZXIgaW5jaWRlbnRzLCBwbGVhc2UgZW1haWwgSzEyc3NkYkBjaGRzLnVzLiIKClRvIGRvIHRoaXMsIHdlIGNhbiB1c2UgdGhlIGBza2lwYCBhcmd1bWVudCBvZiB0aGlzIGZ1bmN0aW9uIGFuZCBzcGVjaWZ5IHRoYXQgd2Ugd2lzaCB0byBvbmx5IHNraXAgMSByb3cgd2l0aCBgc2tpcCA9IDFgLiBXZSBjYW4gYWxzbyBzcGVjaWZ5IHRoYXQgdGhlIG5leHQgcm93IHNob3VsZCBiZSB1c2VkIGZvciBjb2x1bW4gbmFtZXMgdXNpbmcgdGhlIGBjb2xfbmFtZXMgPSBUUlVFYCBhcmd1bWVudC4gCgoKYGBge3J9CgpzaG9vdGluZ19kYXRhIDwtIHJlYWRyOjpyZWFkX2NzdihmaWxlID0gaGVyZTo6aGVyZSgicmF3X2RhdGEiLCAiSy0xMl9TU0RCXyhQdWJsaWMpLUstMTJfU1NEQl8oUHVibGljKV9MaW5rZWQuY3N2IiksIGNvbF9uYW1lcyA9IFRSVUUsIHNraXAgPSAxKQpgYGAKCgpXZSBjYW4gdXNlIHRoZSBgZ2xpbXBzZWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byB0YWtlIGEgbG9vayBhdCBjb2x1bW5zIHdpdGhpbiB0aGUgZGF0YWJhc2U6CgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojIFNjcm9sbCB0aHJvdWdoIHRoZSBvdXRwdXQhCmdsaW1wc2Uoc2hvb3RpbmdfZGF0YSkKYGBgCgojIyMjCgpXZSBjYW4gYWxzbyB1c2UgdGhlIHV0aWxzIGBzdHIoKWAgZnVuY3Rpb24gdG8gc2VlIG1vcmUgZGV0aWFscyBhYm91dCB0aGUgdmFsdWVzLiBUeXBpY2FsbHkgd2Ugd291bGQgYmUgYWJsZSB0byBzZWUgdGhlc2Ugd2l0aCBgZ2xpbXBzZSgpYCBidXQgc29tZSBvZiB0aGUgY29sdW1ucyBoYXZlIHZlcnkgbG9uZyBuYW1lcywgdGh1cyBvYnNjdXJpbmcgdGhlIGZpcnN0IGZldyB2YWx1ZXMgaW4gdGhlIG91dHB1dC4KCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CiMgU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKc3RyKHNob290aW5nX2RhdGEpCmBgYAoKIyMjIwoKIyMgKipEYXRhIEV4cGxvcmF0aW9uIGFuZCBXcmFuZ2xpbmcqKgoqKioKTHVja2lseSwgb3VyIGRhdGEgaXMgYWxyZWFkeSBpbiBwcmV0dHkgZ29vZCBzaGFwZSwgYnV0IHdlIHdhbnQgdG8gbWFrZSBvdXIgZGF0YSBtb3JlIHVzZWZ1bCBmb3Igb3VyIGRhc2hib2FyZC4gCgojIyMgQWRkaW5nIHN0YXRlIG5hbWUKCkl0IHdvdWxkIGJlIHVzZWZ1bCB0byBoYXZlIHRoZSBmdWxsIHN0YXRlIG5hbWUgaW4gb3VyIGRhdGEsIHJhdGhlciB0aGFuIGp1c3QgdGhlIGFiYnJldmlhdGlvbi4KCldlIGNhbiBkbyBzbyBieSB1c2luZyBkYXRhIHJlbGF0ZWQgdG8gdGhlIFVTIDUwIHN0YXRlcyBpbiBhIGRhdGFzZXQgY2FsbGVkIGBzdGF0ZWAgdGhhdCBpcyBhdXRvbWF0aWNhbGx5IGxvYWRlZCB3aXRoIFIgc2Vzc2lvbnMgaW4gdGhlIGBkYXRhc2V0c2AgcGFja2FnZS4gVGhlIGBzdGF0ZS5hYmJgIG9iamVjdCBpcyBhIGxpc3Qgb2YgdGhlIHN0YXRlIGFiYnJldmlhdGlvbnMgYW5kIGBzdGF0ZS5uYW1lYCBpcyBhIGxpc3Qgb2YgdGhlIHN0YXRlIG5hbWVzLgoKYGBge3J9CnN0YXRlLmFiYgpzdGF0ZS5uYW1lCmBgYAoKV2Ugd2lsbCBjb21iaW5lIHRoZXNlIHVzaW5nIHRoZSBgdGliYmxlKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGliYmxlKClgIHBhY2thZ2UuIAoKYGBge3J9CnN0YXRlX2RmIDwtIHRpYmJsZShTdGF0ZV9hYmIgPSBzdGF0ZS5hYmIsIFN0YXRlID0gc3RhdGUubmFtZSkKCnNsaWNlX2hlYWQoc3RhdGVfZGYsIG49IDQpCmBgYAoKTm93IHdlIHdpbGwgY29tYmluZSB0aGlzIHdpdGggb3VyIGRhdGEgdXNpbmcgdGhlIGBsZWZ0X2pvaW4oKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gYXZvY2FkbyBhZGQgZXhwbGFuYXRpb24gYW5kIGpvaW4gaW1hZ2VzCmh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvam9pbi5odG1sCgoKYGBge3J9CnNob290aW5nX2RhdGEgJTw+JQogIHJlbmFtZSgiU3RhdGVfYWJiIiA9IFN0YXRlKSAlPiUKICBsZWZ0X2pvaW4oc3RhdGVfZGYsIGJ5ID0gYygiU3RhdGVfYWJiIiA9ICJTdGF0ZV9hYmIiKSkKYGBgCgpgYGB7cn0Kc2hvb3RpbmdfZGF0YSAlPiUKICBzZWxlY3QoU2Nob29sLCBDaXR5LCBTdGF0ZV9hYmIsIFN0YXRlKSAlPiUKICBzbGljZV9oZWFkKG4gPSA0KQpgYGAKCiMjIyBSZWZvcm1hdGluZyBkYXRlcwpXZSBhbHNvIHdhbnQgdG8gcmVmb3JtYXQgb3VyIGRhdGUgdmFsdWVzIGFuZCBjcmVhdGUgYSBgRGF0ZV95ZWFyYCB2YXJpYWJsZSBiYXNlZCBvbiB0aGUgeWVhciBpbiBlYWNoIGRhdGUuIFdlIGNhbiB1c2UgdGhlIGBsdWJyaWRhdGVgIHBhY2thZ2UgZm9yIHRoaXMuCgpUaGUgYG1keSgpYCBmdW5jdGlvbiBjb252ZXJ0cyBkYXRlcyBpbnRvIGEgZm9ybWF0IHdoZXJlIGRhdGVzIGFyZSBsaXN0ZWQgYXMgbW9udGgsIGRhdGUsIGFuZCB5ZWFyIHdpdGggaHlwaGVucyBpbiBiZXR3ZWVuLgpUaGUgYHllYXIoKWAgZnVuY3Rpb24gY2FuIHRoZW4gYmUgdXNlZCB0byBleHRyYWN0IGp1c3QgdGhlIHllYXIgZnJvbSBlYWNoIGRhdGUuCgpgYGB7cn0Kc2hvb3RpbmdfZGF0YSAlPD4lCiAgICAgICBtdXRhdGUoRGF0ZSA9IGx1YnJpZGF0ZTo6bWR5KERhdGUpKSAlPiUKICBtdXRhdGUoRGF0ZV95ZWFyID0gbHVicmlkYXRlOjp5ZWFyKERhdGUpKQoKc2hvb3RpbmdfZGF0YSAlPiUgc2VsZWN0KERhdGUsIERhdGVfeWVhcikKYGBgCkxvb2tzIGdvb2QhCgpPbmUgbGFzdCB0aGluZyB0byBkbyBpcyB0byBjb252ZXJ0IGBZZXNgIGFuZCBgTm9gIHZhbHVlcyBpbnRvIGBUUlVFYCBhbmQgYEZBTFNFYC4KCgpGaXJzdCBsZXQncyB0YWtlIGEgbG9vayBhdCBvdXIgZGF0YToKCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CnN0cihzaG9vdGluZ19kYXRhKQoKYGBgCgojIyMjCgpXZSBzZWUgdGhhdCBtYW55IG9mIHRoZSB2YXJhaWJsZXMgaGF2ZSBlaXRoZXIgYFllc2Agb3IgYE5vYCB2YWx1ZXMgb3IgYFlgIGFuZCBgTmAgdmFsdWVzLiAgVGhlc2UgYXJlIHRoZSB2YXJpYWJsZXMgdGhhdCBoYXZlIGBZL05gIGluIHRoZSBuYW1lIG9yIHRoZSBgVGFyZ2V0ZWQgU3BlY2lmaWMgVmljdGltKHMpYCwgYFJhbmRvbSBWaWN0aW1zYCwgYFByZS1wbGFubmVkIHNjaG9vbCBhdHRhY2tgIHZhcmlhYmxlcy4gV2UgY2FuIG1ha2UgdGhlc2UgY29uc2lzdGVudGx5IGBUUlVFYCBhbmQgYEZBTFNFYCBieSB1c2luZyB0aGUgYGNhc2Vfd2hlbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzcGVjaWZ5IG5ldyB2YWx1ZXMgZm9yIGV4aXN0aW5nIHZhbHVlcywgc2ltbGFybHkgdG8gdGhlIGByZWNvZGUoKWAgZnVuY3Rpb24gYWxzbyBvZiBgZHBseXJgLiBUaGUgYmVuZWZpdCBvZiB0aGUgYGNhc2Vfd2hlbigpYCBmdW5jdGlvbiwgaXMgdGhhdCBjaGFuZ2luZyB0aGUgdmFsdWVzIHRvIGBUUlVFYCBvciBgRkFMU0VgIGFsc28gcmVzdWx0cyBpbiB0aGUgY2xhc3MgdHlwZSBvZiB0aGUgdmFyaWFibGUgY2hhbmdpbmcgdG8gdHlwZSBsb2dpY2FsICh3aGljaCBpcyBpbnRlcnByZXRlZCBhcyBhIGJpbmFyeSB2YXJpYWJsZSB3aXRoIGBUUlVFYCBhbmQgYEZBTFNFYCB2YWx1ZXMpIG90aGVyd2lzZSwgd2l0aCBgcmVjb2RlKClgIHRoZSB2YXJpYWJsZXMgd291bGQgcmVtYWluIGFzIGNsYXNzIHR5cGUgY2hhcmFjdGVyLiAKCjxkZXRhaWxzPjxzdW1tYXJ5PiBjbGljayBoZXJlIGZvciBtb3JlIGRldGFpbHMgYWJvdXQgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gYHJlY29kZSgpYCBhbmQgY2FzZV93aGVuKClgPC9zdW1tYXJ5PgoKYXZvY2FkbyBjaGVjayBvbiB0aGVzZSBzdGF0ZW1lbnRzICAtIHRoaXMgZG9lcyBub3Qgc2VlbSB0byBiZSB0cnVlIGZvciBjYXNlX3doZW4gZGVzcGl0ZSB3aGF0IHRoZSBkb2N1bWVudGF0aW9uIHNheXMgIklmIG5vIGNhc2VzIG1hdGNoLCBOQSBpcyByZXR1cm5lZC4iCgpOb3RlLCB0aGF0IHdpdGggYHJlY29kZSgpYCB0aGVyZSBpcyB0aGUgb3B0aW9uIHRoYXQgb3RoZXIgdmFsdWVzIGJlIHJlY29kZWQgdG8gYE5BYCBhbHRob3VnaHQgdGhpcyBpcyBub3QgdGhlIGRlZmF1bHQsIGhvd2V2ZXIgd2l0aCBgY2FzZV93aGVuKClgIG90aGVyIHZhbHVlcyBub3QgZXhwbGljaXRseSBhc3NpZ25lZCBpbiB0aGUgY2FzZV93aGVuKCkgc3RhdGVtZW50IHdpbGwgYmUgYE5BYC4gRnVydGhlciBtb3JlIG9ubHkgdmFsdWVzIGNhbiBiZSB1c2VkIG9uIHRoZSBsZWZ0IHNpZGUgd2hlbiB1c2luZyBgcmVjb2RlKClgIHdoZXJlYXMgYGNhc2Vfd2hlbigpYCBhY2NlcHRzIGV4cHJlc3Npb25zIHRoYXQgbmVlZCB0byBiZSBldmFsdWF0ZWQsIHVubGVzcyB1c2luZyB0aGUgYDo9YCBvcHBlcmF0b3IuPz8/CgoKKioqCgo8L2RldGFpbHM+Cgphdm9jYWRvIGFkZCBsaW5rcyBhYm91dCB0aGlzLyBtYXliZSBhZGQgL2NoZWNrIGlmIHdlIGFscmVhZHkgYWRkZWQgdGhlIGNsYXNzIHR5cGUgc3R1ZmYgZnJvbSB0aGUgb3RoZXIgY2FzZSBzdHVkaWVzIC0gaW5kZWVkIGNhc2V3aGVuIGluIG90aGVyIGNhc2VzIHNlZW1zIHRvIGF1dG9tYXRpY2FsbHkgbWFrZSBhbGwgb3RoZXIgY2FzZXMgTkEgYnV0IHdhcyB0aGF0IHRoZSBjYXNlIGhlcmU/CgpUbyBpbXBsZW1lbnQgdGhlIGBjYXNlX3doZW4oKWAgcmVjb2Rpbmcgb2YgdmFsdWVzLCB0aGUgZXhpc2l0aW5nIHZhbHVlcyBhcmUgd3JpdHRlbiBvbiB0aGUgbGVmdCBvZiB0aGUgYH5gIHNpZ24gKHF1b3RhdGlvbiBtYXJrcyBuZWNlc3NhcnkpIGFuZCBuZXcgdmFsdWVzIGFyZSB3cml0dGVuIG9uIHRoZSByaWdodCAocXVvdGF0aW9ucyBtYXJrcyBhcmUgbm90IG5lY2Vzc2FyeSBhcyB0aGVzZSBhcmUgYFRSVUVgIGFuZCBgRkFMU0VgIHN0YXRtZW50cykuIFdlIHdpbGwgYWxzbyB1c2UgdGhlIGBhY3Jvc3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSBhbmQgdGhlIGBtYXRjaGVzKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXNlbGVjdGAgcGFja2dlIHRvIGFsbG93IHVzIHRvIGFwcGx5IHRoaXMgdG8gYWxsIG9mIHRoZSB2YXJpYWJsZXMgdGhhdCBoYXZlIGEgcGF0dGVybiB0aGF0IHRoYXQgbWF0Y2hlcyBhbnkgb2YgdGhvc2Ugb2YgdGhlIHZhcmlhYmxlcyB3ZSB3YW50IHRvIGNoYW5nZS4gVGhlIGB8YCBzeW1ib2wgaXMgaW50ZXJwcmV0ZWQgYXMgYW4gb3IsIHRodXMgYW55IHZhcmlhYmxlcyB0aGF0IGhhcyBhIG5hbWUgdGhhdCBtYXRjaGVzIGFueSBvZiB0aGVzZSBwYXR0ZXJucyB3aWxsIGJlIGNoYW5nZWQuIGZUaGUgYGFjcm9zcygpYCBmdW5jdGlvbiB0aGVuIGFwcGxpZXMgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gdG8gYWxsIG9mIHRoZXNlIHZhcmlhYmxlcy4gTm90aWNlIHRoYXQgdGhlIGB+YCBzeW1ib2wgaXMgbmVjZXNzYXJ5IGJlZm9yZSB0aGUgZnVudGlvbiB0aGF0IGlzIGFwcGxpZWQgdXNpbmcgYGFjcm9zcygpYC4KYGBge3J9CgpEVDo6ZGF0YXRhYmxlKHNob290aW5nX2RhdGEpCmBgYAoKCmBgYHtyfQoKc2hvb3RpbmdfZGF0YSAlPiUgZmlsdGVyKGBUYXJnZXRlZCBTcGVjaWZpYyBWaWN0aW0ocylgID09ICJObyB2aWN0b21zIikKCnNob290aW5nX2RhdGElPiUgc2VsZWN0KG1hdGNoZXMoIlkvTnxTcGVjaWZpY3xSYW5kb218UHJlLXBsYW5uZWQiKSkKCnNob290aW5nX2RhdGEgJTw+JQogICAgICAgbXV0YXRlKGRwbHlyOjphY3Jvc3MoLmNvbHMgPSBtYXRjaGVzKCJZL058U3BlY2lmaWN8UmFuZG9tfFByZS1wbGFubmVkIiksCiAgICAgICAgICAgICAgICAgICAgfiBkcGx5cjo6Y2FzZV93aGVuKC4gPT0gIlllcyIgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC49PSAiTm8iIH4gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC49PSAiWSIgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuPT0gIk4iIH4gVFJVRSkpKQoKc2hvb3RpbmdfZGF0YSAlPiUgc2VsZWN0KG1hdGNoZXMoIlkvTnxTcGVjaWZpY3xSYW5kb218UHJlLXBsYW5uZWQiKSkKCnNob290aW5nX2RhdGEgJT4lIGZpbHRlcihgVGFyZ2V0ZWQgU3BlY2lmaWMgVmljdGltKHMpYCA9PSAiTm8gdmljdG9tcyIpCmBgYAoKCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQpzdHIoc2hvb3RpbmdfZGF0YSkKCmBgYAoKIyMjIwoKTG9va3MgZ29vZCEKCgoKZnJvbSBNaWNoYWVsOgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHJlYWRfY3N2KGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YS5jc3YiKSkKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogIGZpbHRlcighaXMubmEobG9uZ2l0dWRlKSwKICAgICAgICAgIWlzLm5hKGxhdGl0dWRlKSkgJT4lCiAgc2Y6OnN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbmdpdHVkZSIsICJsYXRpdHVkZSIpLCBjcnMgPSA0MzI2KSAlPiUKICAKICBzdF90cmFuc2Zvcm0oY3JzID0gMTAyMDA4KSAlPiUKICBzdF9qaXR0ZXIoYW1vdW50ID0gNTApICU+JQogIHN0X3RyYW5zZm9ybShjcnMgPSA0MzI2KSAlPiUKICBtdXRhdGUobG9uZ2l0dWRlID0gc3RfY29vcmRpbmF0ZXMoLilbLDFdLAogICAgICAgICBsYXRpdHVkZSA9IHN0X2Nvb3JkaW5hdGVzKC4pWywyXSkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtZ2VvbWV0cnkpCgpzdGF0ZV9kZiA8LSBhc190aWJibGUoY2JpbmQoc3RhdGUuYWJiLCBzdGF0ZS5uYW1lKSkKCnNob290aW5nX2RhdGFfZ2VvY29kZWQgPC0gc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCAlPiUKICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikpICU+JQogIG11dGF0ZShEYXRlX3llYXIgPSB5ZWFyKERhdGUpKSAlPiUKICByZW5hbWUoIlN0YXRlX2FiYiIgPSBTdGF0ZSkgJT4lCiAgbGVmdF9qb2luKHN0YXRlX2RmLCBieSA9IGMoIlN0YXRlX2FiYiIgPSAic3RhdGUuYWJiIikpICU+JQogIHJlbmFtZSgiU3RhdGUiID0gc3RhdGUubmFtZSkgJT4lCiAgbXV0YXRlKFN0YXRlID0gc3RyX3RvX3RpdGxlKHRvbG93ZXIoU3RhdGUpKSkgJT4lCiAgbXV0YXRlKGBTdWljaWRlIChvciBhdHRlbXB0ZWQgc3VpY2lkZSkgYnkgU2hvb3RlciAoWS9OKWAgPSBjYXNlX3doZW4oYFN1aWNpZGUgKG9yIGF0dGVtcHRlZCBzdWljaWRlKSBieSBTaG9vdGVyIChZL04pYCA9PSAiWWVzIiB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSkKCnN0YXJ0IDwtIDE5NzAKZW5kIDwtIDIwMjAKCndyaXRlX2NzdihzaG9vdGluZ19kYXRhX2dlb2NvZGVkLCBwYXRoID0gaGVyZSgicHJvY2Vzc2VkX2RhdGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNob290aW5nX2RhdGFfd3JhbmdsZWQuY3N2IikpCgpybShzaG9vdGluZ19kYXRhX2dlb2NvZGVkKQoKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSByZWFkX2NzdihoZXJlKCJwcm9jZXNzZWRfZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YV93cmFuZ2xlZC5jc3YiKSkKYGBgCgoKCgpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGluIGNyZWF0aW5nIGEgbWFwIG9uIG91ciBkYXNoYm9hcmQuIAoKVG8gZG8gc28gd2UgbmVlZCB0byBwZXJmb3JtIGEgcHJvY2VzcyBjYWxsZWQgW2dlb2NvZGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2VvY29kaW5nKS4gR2VvY29kaW5nIGlzIHRoZSBwcm9jZXNzIG9mIGNvbnZlcnRpbmcgYWRkcmVzc2VzIGludG8gbGF0aXR1ZGUgYW5kIGxvbmd0aXR1ZGUgY29vcmRpbmF0ZXMuCgojIyMgR2VvY29kaW5nIHdpdGggdGhlIGBnZ21hcGAgcGFja2FnZQoKVG8gcGVmb3JtIHRoZSBnZW9jb2Rpbmcgd2UgbmVlZCB0aGUgYWRkcmVzcyBvZiBlYWNoIHNjaG9vbCBpbiB0aGUgZGF0YSBzZXQuIFRoZSBkYXRhIGN1cnJlbnRseSBkb2VzIG5vdCBsaXN0IHRoZSBhY3R1YWwgYWRkcmVzcywgYnV0IGRvZXMgaGF2ZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc2Nob29sIHdoZXJlIHRoZSBldmVudCBvY2N1cmVkLiBTaW5jZSBzb21lIHNjaG9vbHMgaGF2ZSB0aGUgc2FtZSBuYW1lLCB3ZSBuZWVkIHRoZSBjaXR5IGFuZCBzdGF0ZSBkYXRhIGFzIHdlbGwuIFNvIHdlIHdpbGwgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGluIG91ciBkYXRhIGNhbGxlZCBgYWRkcmVzc2AgdXNpbmcgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gVGhpcyB2YXJpYWJsZSB3aWxsIGNvbGxhcHNlIHRoZSB2YWx1ZXMgaW4gdGhlIGBTY2hvb2xgLCBgQ2l0eWAsIGFuZCBgU3RhdGVgIGNvbHVtbnMgYnV0IHdpdGggc3BhY2VzIGluIGJldHdlZW4uIEl0IGlzIHNwZWNpZmllZCB0aGF0IHRoZXJlIHdpbGwgYmUgc3BhY2UgaW4gYmV0d2VlbiBieSB0aGUgYHNlcCA9ICIgImAgYXJndW1lbnQuIE5vdGUgdGhhdCBhIHNwYWNlIGlzIHR5cGVkIGJldHdlZW4gdGhlIHF1b3RhdGlvbiBtYXJrcy4gVGhlbiB3ZSBjYW4gdXNlIHRoZSBhZGRyZXNzIHZhcmlhYmxlIHRvIGxvb2sgdXAgdGhlIGxhdGl0dWRlIGFuZCBsb25ndGl0dWRlIGZvciBlYWNoIHNjaG9vbC4KCgpgYGB7cn0Kc2hvb3RpbmdfZGF0YSAlPD4lCiAgZHBseXI6Om11dGF0ZShhZGRyZXNzID0gCiAgICAgICAgICBzdHJpbmdyOjpzdHJfYyhTY2hvb2wsIENpdHksIFN0YXRlX2FiYiwgc2VwID0gIiAiKSkKCmBgYAoKTm90aWNlIHRoYXQgd2UgdXNlZCBhIGAlPiVgIGluIHRoZSBwcmV2aW91cyBjaHVuayBvZiBjb2RlLiBUaGlzIGFsbG93cyB1cyB0byBjcmVhdGUgY29kZSB3aXRoIGEgbWV0aG9kIGNhbGxlZCBwaXBpbmcuIAoKSXQgYWxsb3dzIHVzIHRvIHBlcmZvcm0gbWFueSBzZXF1ZW50aWFsIHN0ZXBzIGVmZmljaWVudGx5LgoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT5DbGljayBoZXJlIGlmIHlvdSBhcmUgdW5mYW1pbGlhciB3aXRoIHBpcGluZyBpbiBSLCB3aGljaCB1c2VzIHRoaXMgYCU+JWAgb3BlcmF0b3IuPC9zdW1tYXJ5PiAgCgpCeSBbcGlwaW5nXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpIHdlIG1lYW4gdXNpbmcgdGhlIGAlPiVgIHBpcGUgb3BlcmF0b3Igd2hpY2ggaXMgYWNjZXNzaWJsZSBhZnRlciBsb2FkaW5nIHRoZSBgdGlkeXZlcnNlYCBvciBzZXZlcmFsIG9mIHRoZSBwYWNrYWdlcyB3aXRoaW4gdGhlIHRpZHl2ZXJzZSBsaWtlIGBkcGx5cmAgYmVjYXVzZSB0aGV5IGxvYWQgdGhlIFtgbWFncml0dHJgIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCkuIApUaGlzIGFsbG93cyB1cyB0byBwZXJmb3JtIG11bHRpcGxlIHNlcXVlbnRpYWwgc3RlcHMgb24gb25lIGRhdGEgaW5wdXQuClRoZSBvYmplY3Qgb24gdGhlIGxlZnQgc2lkZSBpcyB1c2VkIGFzIGlucHV0IHRvIGFueSBjb21tYW5kcyB0byB0aGUgcmlnaHQgb3IgYmVsb3cuCgo8L2RldGFpbHM+ICAKKioqCgpXZSBjYW4gdGFrZSBhIGxvb2sgYXQganVzdCB0aGlzIG5ldyBgYWRkcmVzc2AgdmFyaWFibGUgdXNpbmcgdGhlIGBwdWxsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXIoKWAgcGFja2FnZS4KCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CnNob290aW5nX2RhdGEgJTw+JQogIGRwbHlyOjpwdWxsKGFkZHJlc3MpCmBgYAojIyMjIAoKTm93IHdlIGNhbiB1c2UgdGhlc2UgYWRkcmVzc2VzIHRvIGZpbmQgdGhlIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgY29vcmRpbmF0ZXMgZm9yIGVhY2ggc2Nob29sIHdoZXJlIGEgc2Nob29sIHNob290aW5nIG9jY3VyZWQuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBnZW9jb2RlYCBmdW5jdGlvbiBvZiB0aGUgYGdnbWFwYCBwYWNrYWdlIHRvIGxvb2sgdXAgdGhlc2UgYWRkcmVzc2VzIG9uIEdvb2dsZSBNYXBzIHRvIGdldCB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSB2YWx1ZXMuIEluIHRoaXMgY29tbWFuZCB3ZSBuZWVkIHRvIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIHVzZSBnb29nbGUgYXMgdGhlIHNvdXJjZSB1c2luZyB0aGUgYHNvdXJjZWAgYXJndW1lbnQgYW5kIHRoYXQgd2Ugd2FudCBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIHVzaW5nIHRoZSBgb3V0cHV0ID0gYygibGF0bG9uIikgYXJndW1lbnQuCgoKVGhpcyBzdGVwIHJlcXVpcmVzIHJlZ2lzdGVyaW5nIHdpdGggdGhlIEdvb2dsZSBDbG91ZCBQbGF0Zm9ybSB0byBnZXQgYW4gQVBJIGtleSwgd2hpY2ggY3VycmVudGx5IHJlcXVpcmVzIHJlZ2lzdGVyaW5nIHlvdXIgcGF5bWVudCBpbmZvcm1hdGlvbiBhbmQgYWdyZWVpbmcgdG8gdGhlIFtHb29nbGUgTWFwcyBBUEkgVGVybXMgb2YgU2VydmljZV0oaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vbWFwcy90ZXJtcykuCgpUaGVyZWZvcmUsIHdlIHdpbGwgc2ltcGx5IGRlbW9uc3RyYXRlIGhvdyB0aGlzIHByb2Nlc3Mgd29ya3MgaW4gZ2VuZXJhbCwgYnV0IHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGRvIHRoaXMgeW91cnNlbGYuIAoKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGhvdyB3ZSByZWdpc3RlcmVkIHdpdGggdGhlIEdvb2dsZSBDbG91ZCBQbGF0Zm9ybS48L3N1bW1hcnk+CgpJZiB5b3Ugd2VyZSB0byBkbyB0aGlzIHByb2Nlc3MgeW91cnNlbGYsIHlvdSBjb3VsZCBnZXQgYW4gQVBJIGtleSBbaGVyZV0oaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL21hcHMtcGxhdGZvcm0vKS4gQWdhaW4gdGhpcyByZXF1aXJlcyByZWdpc3RlcmluZyB5b3VyIHBheW1lbnQgaW5mb3JtYXRpb24sIGJ1dCBpdCBpcyBmcmVlIHRvIGdvdCBhbiBBUEkga2V5IGFuZCBlbmFibGUgdGhlIEFQSXMsIGhvd2V2ZXIgeW91IGNhbiBiZSBiaWxsZWQgYmFzZWQgb24gaG93IG1hbnkgYWRkcmVzc2VzIHlvdSBsb29rIHVwIHVzaW5nIHRoZSBBUElzLiBZb3UgbmVlZCB0byBsb29rIHVwIHRob3VzYW5kcyBiZWZvcmUgZ2V0dGluZyBiaWxsZWQuCgpUaGVuIHlvdSBuZWVkIHRvIGVuYWJsZSB0aGUgbWFwcyBhbmQgcGxhY2VzIEFQSXMsIGJ5IGNsaWNraW5nIG9uIHRoZSBib3hlcyBuZXh0IHRvIGVhY2g6CgpgYGB7cixlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJlbmFibGUucG5nIikpCmBgYAoKVGhlbiB5b3Ugd291bGQgcmVnaXN0ZXIgbGlrZSBzbyBhZnRlciBjb3B5aW5nIHRoZSBBUEkga2V5OiAoTm90ZSB0aGlzIGlzIGEgZmFrZSBrZXkpCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpnZ21hcDo6cmVnaXN0ZXJfZ29vZ2xlKGtleSA9ICJtUWt6VHBpYUxZalBxWFFCb3Rlc2dpZjNFZkdMMmRick5WT3JvZ2ciKSAKYGBgCgoqKioKPC9kZXRhaWxzPgoKCk9uY2Ugd2UgaGF2ZSBvYnRhaW5lZCBhbiBBUEkga2V5IGFuZCByZWdpc3RlcmVkLCB3ZSBjYW4gZ2VvY29kZSBvdXIgZGF0YS4KCk5vdGUgdGhhdCB0aGlzIHN0ZXAgaXMgdGltZSBpbnRlbnNpdmUsIGFzIHRoZXJlIGFyZSBtYW55IGFkZHJlc3NlcyB0byBsb29rIHVwISBUaGVyZWZvcmUsIHdlIHdpbGwganVzdCBzaG93IGhvdyB0aGlzIGlzIGRvbmUuCgpgYGB7ciwgZXZhbD1GQUxTRX0KCnNob290aW5nX2RhdGEgPC0gc2hvb3RpbmdfZGF0YSAlPiUKICBtdXRhdGUoY29vcmRzID0gZ2dtYXA6Omdlb2NvZGUoYWRkcmVzcywgb3V0cHV0ID0gYygibGF0bG9uIiksIHNvdXJjZSA9IGMoImdvb2dsZSIpKSkKCnJlYWRyOjp3cml0ZV9jc3Yoc2hvb3RpbmdfZGF0YSwgcGF0aCA9IGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNob290aW5nX2RhdGFfZ2VvLmNzdiIpKQoKYGBgCgpUaGlzIHJlc3VsdHMgaW4gdGliYmxlIGNhbGxlZCBgY29vcmRzYCBiZWluZyBhZGRlZCB0byBvdXIgYHNob290aW5nX2RhdGFgIHRpYmJsZS4gVGhhdCdzIHJpZ2h0IHdlIGNhbiBoYXZlIGEgdGliYmxlIGFzIGEgY29sdW1uIG9yIHZhcmlhYmxlIHdpdGhpbiBhIHRpYmJsZS4gICBVc2luZyB0aGUgYGdsaW1wc2VgIGZ1bmN0aW9uIGFnYWluLCBhbmQgbG9va2luZyBhdCB0aGUgbGFzdCBmZXcgdmFyaWFibGVzLCB3ZSBjYW4gc2VlIHRoYXQgbm93IHRoZSBsYXN0IHZhcmlhYmxlIGxpc3RlZCBpcyBgY29vcmRzYCBvZiBjbGFzcyBgPHRpYmJsZT5gLgoKYGBge3IsZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJzaG9vdGluZ19kYXRhX2Nvb3Jkcy5wbmciKSkKYGBgCgpJZiB3ZSB0YWtlIGEgbG9vayBhdCB0aGUgZmlyc3QgY291cGxlIG9mIHZhbHVlcyBvZiB0aGUgYGNvb3Jkc2AgdGliYmxlLCB1c2luZyB0aGUgYHNsaWNlX2hlYWQoKWAgZnVuY3Rpb24gb2YgdGhlIGRwbHlyIHBhY2thZ2UsIHdlIHNlZSBhIHRpYmJsZSB0aGF0IGxvb2tzIGxpa2UgdGhpczoKCgpgYGB7cixlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iMzAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImNvb3Jkcy5wbmciKSkKYGBgCgoKSXQgd291bGQgYmUgYmV0dGVyIGlmIGVhY2ggb2YgdGhlc2Ugd2VyZSB0aGVpciBvd24gY29sdW1ucyBpbiB0aGUgdGliYmxlLCBzbyB3ZSB3aWxsIGNyZWF0ZSBuZXcgYGxvbmdpdHVkZWAgYW5kIGBsYXRpdHVkZWAgdmFyaWFibGVzIGFnYWluIHVzaW5nIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiBsaWtlIHNvOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc2hvb3RpbmdfZGF0YSA8LSBzaG9vdGluZ19kYXRhICU+JQogIG11dGF0ZShsb25naXR1ZGUgPSBwdWxsKGNvb3Jkcyxsb24pLAogICAgICAgICBsYXRpdHVkZSA9IHB1bGwoY29vcmRzLGxhdCkpCmBgYAoKSW4gdGhpcyBjYXNlIHdlIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gdG8gZ3JhYiB0aGUgYGxhdGAgYW5kIGBsb25gIHZhcmlhYmxlcyB3aXRoaW4gdGhlIGBjb29yZHNgIHRpYmJsZSB3aGljaCBpcyBhIHZhcmlhYmxlIG9mIHRoZSBgc2hvb3RpbmdfZGF0YWAgdGliYmxlLgoKV2UgY2FuIG5vdyByZW1vdmUgdGhlIGBjb29yZHNgIHRpYmJsZSBsaWtlIHNvLCB1c2luZyB0aGUgYHNlbGVjdCgpYCBmdW50aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2U6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfSAgCnNob290aW5nX2RhdGEgPC0gc2hvb3RpbmdfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jb29yZHMpCgpgYGAKCgpOb3cgdXNpbmcgYGdsaW1wc2UoKWAgYW5kIGxvb2tpbmcgYXQgdGhlIGxhc3Qgc2V2ZXJhbCB2YXJpYWJsZXMsIHdlIGNhbiBzZWUgdGhhdCB3ZSBubyBsb25nZXIgaGF2ZSBhIGBjb29yZHNgIHZhcmlhYmxlLCBidXQgd2UgZG8gaGF2ZSB0d28gdmFyaWFibGVzIGNhbGxkIGBsb25naXR1ZGVgIGFuZCBgbGF0aXR1ZGVgIHRoYXQgYXJlIG9mIGNsYXNzIGRvdWJsZSBhcyBpbmRpY2F0ZWQgYnkgdGhlIGA8ZGJsPmA6CgpgYGB7cixlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImRvdWJsZS5wbmciKSkKYGBgCgoKTm93IHdlIHdpbGwgc2F2ZSB0aGUgZ2VvY29kZWQgZGF0YSBpbiB0aGUgYHByb2Nlc3NlZF9kYXRhYCBkaXJlY3RvcnkgdXNpbmcgdGhlIGB3cml0ZV9jc3ZgIGZ1bmN0aW9uIG9mIHRoZSBgcmVhZHJgIHBhY2thZ2UuCgpUaGlzIHJlcXVpcmVzIGxpc3RpbmcgdGhlIFIgb2JqZWN0LCBmb2xsb3dlZCBieSB0aGUgcGF0aCBmb3Igd2hlcmUgdGhlIGZpbGUgc2hvdWxkIGJlIHNhdmVkIGFuZCB3aGF0IGl0IHNob3VsZCBiZSBjYWxsZWQuIEluIHRoaXMgY2FzZSBpdCB3aWxsIGJlIGNhbGxlZCAic2hvb3RpbmdfZGF0YS5jc3YiLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0gCnJlYWRyOjp3cml0ZV9jc3Yoc2hvb3RpbmdfZGF0YSwgcGF0aCA9IGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNob290aW5nX2RhdGFfZ2VvLmNzdiIpKQoKYGBgCgoKR3JlYXQgbm93IHdlIHdpbGwgd29yayB3aXRoIHRoaXMgZGF0YSwgdGh1cyB5b3UgZG8gbm90IG5lZWQgdG8gZ2V0IGFuIEFQSSBrZXkgdG8gZ2V0IHRvIHRoaXMgcG9pbnQuIFdlIGNhbiByZWFkIG91ciBwcm9jZXNzZWQgZ2VvY29kZWQgZGF0YSBpbnRvIFIgYnkgdXNpbmcgdGhlIGByZWFkX2NzdigpYCBmdW5jdGlvbiBvZiB0aGUgYHJlYWRyYCBwYWNrYWdlLgoKYGBge3J9CgpzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHJlYWRfY3N2KGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YV9nZW8uY3N2IikpCmBgYAoKCk5lZWQgdG8gam9pbiBvdXIgd3JhbmdsZWQgZGF0YSB3aXRoIHRoZSBsYXQvbG9uZyBkYXRhIApgYGB7ciwgZXZhbCA9IEZBTFNFfQoKaW5uZXJfam9pbihzaG9vdGluZ19kYXRhX2dlb2NvZGVkLCBzaG9vdGluZ19kYXRhLCBieSA9IGMoIk5hcnJhdGl2ZSAoRGV0YWlsZWQgU3VtbWFyeS8gQmFja2dyb3VuZCkiID0gIk5hcnJhdGl2ZSAoRGV0YWlsZWQgU3VtbWFyeS8gQmFja2dyb3VuZCkiICkpCmBgYAoKCiMjIyBHZW9tZXRyeSBsaXN0cyB3aXRoIHRoZSBgc2ZgIHBhY2thZ2UKCkZyb20gdGhpcyBzZWN0aW9uIG9uLCB3ZSBhcmUgbm93IGdvaW5nIHRvIHVzZSBhIHNwZWNpYWwgcGlwZSBvcGVyYXRvciBmcm9tIHRoZSBbYG1hZ3JpdHRyYCBwYWNrYWdlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpIGNhbGxlZCB0aGUgY29tcG91bmQgYXNzaWdubWVudCBwaXBlLW9wZXJhdG9yIG9yIHNvbWV0aW1lcyB0aGUgZG91YmxlIHBpcGUgb3BlcmF0b3IsIHRoYXQgbG9va3MgbGlrZSB0aGlzIGAlPD4lYC4gCgpUaGlzIGFsbG93cyB1cyB0byB1c2UgdGhlIGFuIGlucHV0IGFuZCByZWFzc2lnbiBpdCBhdCB0aGUgZW5kIGFmdGVyIGFsbCB0aGUgc3Vic2VxdWVudCBzdGVwcyBoYXZlIGJlZW4gcGVyZm9ybWVkLiBXZSBjYW4gdGhlcmVmb3JlIHVzZSBgZGF0YV9pbnB1dCAlPD4lYCBpbnN0ZWFkIG9mIGBkYXRhX2lucHV0IDwtIGRhdGFfaW5wdXQgJT4lYC4gV2Ugd2lsbCBkZW9tb25zdHJhdGUgdGhpcyBpbiB0aGUgY29kZSBiZWxvdy4KCldlIHdpbGwgdXNlIHRoZSBgc2ZgICh3aGljaCBzdGFuZHMgZm9yIHNpbXBsZSBmZWF0dXJlcykgcGFja2FnZSB0byAKY3JlYXRlIHdoYXQgaXMgY2FsbGVkIGEgZ2VvbWV0cnkgbGlzdCBvZiBvdXIgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSAgaW5mb3JtYXRpb24gZm9yIHRoZSBzY2hvb2xzIHdoZXJlIHNob290aW5ncyBvY2N1cmVkLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gY3JlYXRlIGEgbWFwIG9mIHRoZXNlIGV2ZW50cy4KCgpUaGUgZmlyc3QgdGhpbmcgd2UgbmVlZCB0byBkbyBpcyBjcmVhdGUgYW4gc2Ygb2JqZWN0IChtZWFuaW5nIGFuIG9iamVjdCB0aGF0IHRoZSBgc2ZgIHBhY2thZ2UgcmVjb2duaXplcykgdXNpbmcgdGhlIGBzdF9hc19zZigpYCBmdW5jdGlvbi4KCkhvd2V2ZXIsIHRvIGRvIHRoaXMgd2UgZmlyc3QgbmVlZCB0byByZW1vdmUgcm93cyB3aXRoIGBOQWAgdmFsdWVzIGZvciB0aGUgYGxhdGl0dWRlYCBhbmQgYGxvbmdpdHVkZWAgdmFyaWFibGVzLiBJbiBvdGhlcndvcmRzLCB3ZSBuZWVkIHRvIHJlbW92ZSByb3dzIG9mIGV2ZW50cyB0aGF0IGhhcHBlbmVkIGF0IHNjaG9vbHMgd2l0aCBsb2NhdGlvbnMgdGhhdCB3ZXJlIG5vdCBpZGVudGlmaWVkIGJ5IGdvb2dsZS4gV2UgY2FuIHJlbW92ZSB0aGlzIHJvd3MgdXNpbmcgdGhlIGBkcm9wX25hKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UuIFdlIHdpbGwgdXNlIGEgYC5gIHRvIGluZGljYXRlIHRoYXQgd2Ugd2FudCB0byB1c2UgdGhlIGRhdGEgdGhhdCB3ZSBhcmUgdXNpbmcgYXMgYW4gaW5wdXQgd2l0aCBvdXIgcGlwZSwgYnV0IHRoZW4gd2Ugd2lsbCBzcGVjaWZ5IHRoYXQgd2Ugd2FudCB0byBvbmx5IGRyb3Agcm93cyB3ZXJlIHRoZXJlIGlzIGFuIGBOQWAgdmFsdWUgZm9yIGVpdGhlciB0aGUgYGxhdGl0dWRlYCBvciBgbG9uZ2l0dWRlYCB2YXJpYWJsZXMuCgoKYGBge3J9CmRpbShzaG9vdGluZ19kYXRhX2dlb2NvZGVkKQoKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCAlPiUgZmlsdGVyKGlzLm5hKGxhdGl0dWRlKSkgJT4lc2VsZWN0KG1hdGNoZXMoYygibG9uZyIsICJsYXQiLCAiYWRkIikpKQpgYGAKCmBgYHtyfQoKI3VzaW5nIHByZXZpb3VzIG1ldGhvZDoKIyBzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiMgICAgdGlkeXI6OmRyb3BfbmEoLiwgYyhsYXRpdHVkZSwgbG9uZ2l0dWRlKSkKCiN1c2luZyBtYWdyaXR0ciAlPD4lIGNvbXBvdW5kIGFzc2lnbm1lbnQgcGlwZS1vcGVyYXRvcgpzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU8PiUKIHRpZHlyOjpkcm9wX25hKC4sIGMobGF0aXR1ZGUsIGxvbmdpdHVkZSkpCmBgYAoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGltKHNob290aW5nX2RhdGFfZ2VvY29kZWQpCgpjb2xzX3RvX3NlbGVjdCA8LWMoIlNjaG9vbCIsIkRhdGUiLCJTdGF0ZSIsICJDaXR5IiwgIk5hcnJhdGl2ZSAoRGV0YWlsZWQgU3VtbWFyeS8gQmFja2dyb3VuZCkiLCAiS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKSIpCgpzZXRkaWZmKHNlbGVjdChzaG9vdGluZ19kYXRhLCBjb2xzX3RvX3NlbGVjdCksCiAgICAgICAgc2VsZWN0KHNob290aW5nX2RhdGFfZ2VvY29kZWQsIGNvbHNfdG9fc2VsZWN0KSkKYGBgCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkaWZmZXJlbnQgPC1zZXRkaWZmKHNob290aW5nX2RhdGFbMTo0OF0sIHNob290aW5nX2RhdGFfZ2VvY29kZWRbMTo0OF0pCgpkaWZmX25hcnJhdGl2ZTwtc2V0ZGlmZihzaG9vdGluZ19kYXRhJGBOYXJyYXRpdmUgKERldGFpbGVkIFN1bW1hcnkvIEJhY2tncm91bmQpYCwgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgTmFycmF0aXZlIChEZXRhaWxlZCBTdW1tYXJ5LyBCYWNrZ3JvdW5kKWApCgpgYGAKCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdmFyaWFibGVzIGluIG91ciBkYXRhIHJlbGF0ZWQgdG8gbG9jYXRpb24gYnkgdXNpbmcgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZToKCmBgYHtyfQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogIHNlbGVjdChTY2hvb2wsIENpdHksIFN0YXRlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlKQpgYGAKCldlIGNhbiBzZWUgKHVzaW5nIHRoZSBiYXNlIGBkaW0oKWAgZnVuY3Rpb24pIHRoYXQgdGhlIGRpbWVuc2lvbnMgd2VyZSAxMTU2IHJvd3Mgb2YgNTEgdmFyaWFibGVzLCBidXQgdGhleSBhcmUgbm93IDE1NTEgcm93cyBvZiA1MCB2YXJpYWJsZXMuIFRoaXMgaXMgYmVjdWFzZSA1IGV2ZW50cyBvY2N1cmVkIGF0IHNjaG9vbHMgd2l0aCB1bmlkZW50aWZpZWQgY29tcGxldGUgbG9jYXRpb25zIChtaXNzaW5nIGVpdGhlciBsYXRpdHVkZSwgbG9uZ2l0dWRlLCBvciBib3RoKS4gCgpOb3csIHdlIGFyZSByZWFkeSB0byBjb252ZXJ0IG91ciBjb29yZGluYXRlcyB2YXJpYWJsZXMgKGBsYXRpdHVkZWAgYW5kIGBsb25naXR1ZGVgKSBpbnRvIGEgY29vcmRpYW50ZSBzaW1wbGUgZmVhdHVyZSB1c2luZyB0aGUgYHN0X2FzX3NmKClgIGZ1bmN0aW9uLiBXZSBuZWVkIHRvIHNwZWNpZnkgd2hhdCBvdXIgY29vcmRpbmF0ZSB2YXJpYWJsZXMgYXJlIGFuZCB3ZSB3aWxsIGFsc28gc3BlY2lmeSB3aGF0IFtjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1dKGh0dHBzOi8vd3d3LnczLm9yZy8yMDE1L3NwYXRpYWwvd2lraS9Db29yZGluYXRlX1JlZmVyZW5jZV9TeXN0ZW1zKSwoY3JzKSB3ZSB3b3VsZCBsaWtlIHRvIHVzZS4gSW4gb3VyIGNhc2Ugd2Ugd2lsbCB1c2UgdGhlIFtFU1BHXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9FUFNHX0dlb2RldGljX1BhcmFtZXRlcl9EYXRhc2V0KSByZWZlcmVuY2UgbnVtYmVyIFs0MzI2XShodHRwczovL3NwYXRpYWxyZWZlcmVuY2Uub3JnL3JlZi9lcHNnLzQzMjYvKSwga25vd24gYXMgRVNQRzo0MzI2IG9yIHRoZSBbV29ybGQgR2VvZGV0aWMgU3lzdGVtIChXR1MpIHZlcnNpb24gODRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dvcmxkX0dlb2RldGljX1N5c3RlbSNXR1M4NCkgd2hpY2ggaXMgb25lIG9mIHRoZSBtb3N0IGNvbW1vbmx5IHVzZWQgQ1BTIGFuZCB1c2VkIGJ5IGJ5IG1vc3QgZ2xvYmFsIHBvc2l0aW9uaW5nIHN5c3RlbXMsIGtub3duIGFzIEdQUy4gKipUaGlzIHRlbGxzIFIgIHRvIHVzZSB0aGUgdmFsdWVzIGZvciB0aGUgdmFyaWFibGVzIGNhbGxlZCBgbGF0aXR1ZGVgIGFuZCBgbG9uZ2l0dWRlYCBhcyBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvb3JkaW5hdGVzLioqCgpgYGB7cn0Kc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCAlPD4lCiAgc2Y6OnN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbmdpdHVkZSIsICJsYXRpdHVkZSIpLCBjcnMgPSA0MzI2KQoKZGltKHNob290aW5nX2RhdGFfZ2VvY29kZWQpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCBvdXIgYGxhdGl0dWRlYCBhbmQgYGxvbmdpdHVkZWAgdmFyaWFibGVzIHdlcmUgdXNlZCB0byBjcmVhdGUgYSBzaW5nbGUgbmV3IHZhcmlhYmxlIGNhbGxlZCBgZ2VvbWV0cnlgIG9mIGNsYXNzICBgPFBPSU5UYCBbJF57XGNpcmN9JF1gPmAsIHRodXMgd2UgaGF2ZSBvbmUgbGVzcyBjb2x1bW4uCgpJbiB0aGlzIGNhc2UsIHdlIGNhbiB0YWtlIGEgbG9vayBhdCBqdXN0IHRoZSBmaXJzdCA0IHZhcmlhYmxlcyBhbmQgd2Ugd2lsbCBhbHNvIHNlZSBvdXIgbGFzdCBgc2ZgIHZhcmlhYmxlIGFzIHdlbGwgYXBwZW5lZGVkIGF0IHRoZSBlbmQuIFNvIG5vdyB3ZSBjYW4gc2VlIHRoZSB2YXJpYWJsZXMgcmVsYXRlZCB0byBsb2NhdGlvbiBieSBzaW1wbHkgdHlwaW5nIGBbMTo0XWAgbmV4dCB0byB0aGUgbmFtZSBvZiBvdXIgdGliYmxlIGBzaG9vdGluZ19kYXRhX2dlb2NvZGVkYC4KCmBgYHtyfQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkWzE6NF0KYGBgCgoKTm93IHRvIGFsbG93IG91ciBwb2ludHMgdG8gbm90IG92ZXJsYXAgZm9yIGV2ZW50cyB0aGF0IHRvb2sgcGxhY2UgaW4gdGhlIHNhbWUgbG9jYXRpb24sIHdlIHdpbGwgYWRkIGEgYml0IG1vcmUgcmFuZ2Ugc28gdGhhdCB0aGV5IGRvbid0IG92ZXJsYXAgb25lIGFub3RoZXIgb24gb3VyIG1hcCwgd2Ugd2lsbCB0cmFuc2Zvcm0gdGhlIGNvb3JkaW5hdGVzIHVzaW5nIHRoZSBgc3RfdHJhbnNmb3JtKClgIGZ1bmN0aW9uICBvZiB0aGUgYHNmYCBwYWNrYWdlIGludG8gYSB0d28gZGltZW5zaW9uYWwgcHJvamVjdGlvbiAoY2FsbGVkIHRoZSBbQWxiZXJzIGVxdWFsLWFyZWEgY29uaWMgcHJvamVjdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQWxiZXJzX3Byb2plY3Rpb24jOn46dGV4dD1UaGUlMjBBbGJlcnMlMjBlcXVhbCUyRGFyZWElMjBjb25pYyx0aGF0JTIwdXNlcyUyMHR3byUyMHN0YW5kYXJkJTIwcGFyYWxsZWxzLiZ0ZXh0PVRoZSUyMEFsYmVycyUyMHByb2plY3Rpb24lMjBpcyUyMHVzZWQsdGhlJTIwVW5pdGVkJTIwU3RhdGVzJTIwQ2Vuc3VzJTIwQnVyZWF1LikpIHdpdGggdW5pdHMgaW4gbWV0ZXJzIHVzaW5nIHRoZSBbY3JzIDEwMjAwOF0oaHR0cHM6Ly9zcGF0aWFscmVmZXJlbmNlLm9yZy9yZWYvZXNyaS8xMDIwMDgvaHRtbC8pIGFuZCB0aGVuIHVzZSB0aGUgYHN0X2ppdHRlcigpYCBvZiB0aGUgYHNmYCBwYWNrYWdlIGZ1bmN0aW9uCnRvIGFsbG93IGEgc3BlY2lmaWVkIGFtb3VudCBvZiByYW5nZSBuZWFyIHRoZSBhY3R1YWwgb3JpZ2luYWwgR1BTIGNvb3JkaW5hdGVzLiBJbiB0aGlzIGNhc2Ugd2Ugd2lsbCBhbGxvdyBmb3IgNTAgbWV0ZXJzIG9mIHJhbmdlLgoKVG8gbGVhcm4gbW9yZSBhYm91dCBnZW9zcGF0aWFsIGNvb3JkaW5hdGUgc3lzdGVtcyBzZWUgW2hlcmVdKGh0dHBzOi8vd3d3Lm5jZWFzLnVjc2IuZWR1L3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAyMC0wNC9PdmVydmlld0Nvb3JkaW5hdGVSZWZlcmVuY2VTeXN0ZW1zLnBkZikgYW5kIFtoZXJlXShodHRwczovL2d1aWRlcy5saWJyYXJ5LmR1a2UuZWR1L3ItZ2Vvc3BhdGlhbC9DUlMpLgoKU28gaGVyZSB3ZSBjYW4gc2VlIHRoZSBvdXRwdXQgYWZ0ZXIgdHJhbnNmb3JtaW5nIG91ciBkYXRhOgoKYGBge3J9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgICU8PiUKICBzdF90cmFuc2Zvcm0oY3JzID0gMTAyMDA4KSAKYGBgCgpgYGB7cn0Kc2hvb3RpbmdfZGF0YV9nZW9jb2RlZFsxOjRdCmBgYApBbmQgaGVyZSB3ZSBjYW4gc2VlIHRoZSBvdXRwdXQgYWZ0ZXIgYWRkaW5nIHRoZSBqaXR0ZXI6CgpgYGB7cn0Kc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCAgJTw+JQogICBzdF9qaXR0ZXIoYW1vdW50ID0gNTApCgpzaG9vdGluZ19kYXRhX2dlb2NvZGVkWzE6NF0KYGBgCgpOb3RpY2UgaG93IHRoZSBgZ2VvbWV0cnlgIHZhbHVlcyBoYXZlIGNoYW5nZWQuCgpOb3cgd2Ugd2lsbCB0cmFuc2Zvcm0gb3VyIGNvb3JkaW5hdGVzIGJhY2sgaW50byB0aGUgM0QgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBkZWdyZWUgc3lzdGVtIGFnYWluIHVzaW5nIHRoZSBgc3RfdHJhbnNmb3JtKClgIGZ1bmN0aW9uIGFuZCB0aGUgW0VTUEc6NDMyNl0oaHR0cHM6Ly9zcGF0aWFscmVmZXJlbmNlLm9yZy9yZWYvZXBzZy80MzI2LyksIGNvcnJkaW5hdGUgc3lzdGVtLgoKYGBge3J9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgICU8PiUKICBzdF90cmFuc2Zvcm0oY3JzID0gNDMyNikKCnNob290aW5nX2RhdGFfZ2VvY29kZWRbMTo0XQpgYGAKCk5vdGljZSBob3cgdGhlIGBnZW9tZXRyeWAgdmFyaWFibGVzIGFyZSBkaWZmZXJlbnQgZnJvbSB3aGF0IHRoZXkgd2VyZSBvcmdpbmFsbHkgd2l0aCB0aGlzIGNvb3JkaW5hdGUgc3lzdGVtOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiOTAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImdlb21ldHJ5LnBuZyIpKQpgYGAKCgpOb3cgd2Ugd2lsbCBzZXBhcmF0ZSB0aGUgYGdlb21ldHJ5YCB2YXJpYWJsZSBpbnRvIGBsb25naXR1ZGVgIGFuZCBgbGF0aXR1ZGVgIHZhcmlhYmxlcyBhZ2Fpbi4gV2UgY2FuIHVzZSB0aGUgYCBzdF9jb29yZGluYXRlcygpYCBmdW5jdGlvbiBvZiB0aGUgYHNmYCBwYWNrYWdlIHRvIGV4dHJhY3QgdGhlIGNvb3JkaW5hdGVzIGZyb20gb3VyIHRpYmJsZSBhcyBhIG1hdHJpeC4KCmBgYHtyfQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU8PiUgCiAgbXV0YXRlKGNvb3JkaW5hdGVzID0gYXMudGliYmxlKHN0X2Nvb3JkaW5hdGVzKC4pKSkKCnNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgcHVsbChjb29yZGluYXRlcykgJT4lCiAgc2xpY2VfaGVhZChuID0gNCkKYGBgCgpOb3csIGp1c3QgYXMgd2UgZGlkIHByZXZpb3VzbHkgd2Ugd2lsbCBjcmVhdGUgbmV3IHZhcmlhYmxlcyBjYWxsZWQgYGxhdGl0dWRlYCBhbmQgYGxvbmdpdHVkZWAgZnJvbSB0aGUgYFhgIGFuZCBgWWAgdmFyaWFibGVzIHdpdGhpbiB0aGUgYGNvb3JkaW5hdGVzYCB0aWJibGUgdGhhdCBpcyBwYXJ0IG9mIG91ciBgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZGAgdXNpbmcgdGhlIGBwdWxsKClgIGZ1bmN0aW9uLgoKV2Ugd2lsbCBhbHNvIGNvbnZlcnQgb3VyIGBzaG9vdGluZ19kYXRhX2dlb2NvZGVkYCBvYmplY3Qgd2hpY2ggaXMgY3VycmVudGx5IGEgYHNmYCBpbnRvIGEgdGliYmxlIHVzaW5nIHRoZSBgYXNfdGliYmxlKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGliYmxlYCBwYWNrYWdlIGFuZCB0aGVuIHdlIHdpbGwgcmVtb3ZlIHRoZSBgZ2VvbWV0cnlgIGFuZCBgY29vcmRpbmF0ZXNgIHZhcmlhYmxlcyB1c2luZyB0aGUgYHNlbGVjdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHdpdGggYSBuZWdhdGl2ZSBzaWduIGluZnJvbnQgb2YgdGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgdG8gcmVtb3ZlLgoKYGBge3J9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgJTw+JQogIG11dGF0ZShsb25naXR1ZGUgPSBwdWxsKGNvb3JkaW5hdGVzLFgpLAogICAgICAgICAgbGF0aXR1ZGUgPSBwdWxsKGNvb3JkaW5hdGVzLFkpKSAlPiUKICB0aWJibGU6OmFzX3RpYmJsZSgpICU+JQogIHNlbGVjdCgtZ2VvbWV0cnkpICU+JQogIHNlbGVjdCgtY29vcmRpbmF0ZXMpCmBgYAoKQW5kIG5vdyB3ZSBjYW4gdGFrZSBhIGxvb2sgYXQgIG91ciBsYXN0IDMgdmFyaWFibGVzIHVzaW5nIHRoZSBgbGFzdF9jb2woKWAgZnVuY3Rpb24sIHdoaWNoIGlzIGEgc2VsZWN0IGhlbHBlciBmdW5jdGlvbiBgdGlkeXJgIHBhY2thZ2UuIFNlZSBbaGVyZV0oaHR0cHM6Ly90aWR5c2VsZWN0LnItbGliLm9yZy9yZWZlcmVuY2Uvc2VsZWN0X2hlbHBlcnMuaHRtbCkgZm9yIG90aGVyIHNlbGVjdCBoZWxwZXIgZnVuY3Rpb25zLiBUaGlzIGFsbG93cyB1cyB0byBzZWxlY3QgZWl0aGVyIHRoZSBsYXN0IGNvbHVtbiwgb3Igd2l0aCBhIHNwZWNpZmllZCBvZmZzZXQgd2UgY2FuIHNlbGVjdCBhIG51bWJlciBvZiBjb2x1bW5zIGJlZm9yZSB0aGUgbGFzdCBjb2x1bW4uIFRodXMgMiBjb2x1bW5zIGJlZm9yZSB0aGUgbGFzdCBjb2x1bW4gIHdvdWxkIGJlIGBsYXN0X2NvbChvZmZzZXQgPSAyKWAgYW5kIHRoZW4gdGhlIGA6YCBzeW1ib2wgaXMgaW50ZXJwcmV0ZWQgYXMgdGhyb3VnaCwgdGh1cyB3ZSBhcmUgc2VsZWN0aW5nIGZvciB0aGUgdGhpcmQgdG8gbGFzdCBjb2x1bW4gdGhyb3VnaCB0aGUgbGFzdCBjb2x1bW4gd2l0aCBgbGFzdF9jb2wob2Zmc2V0ID0gMik6IGxhc3RfY29sKClgLgoKYGBge3J9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lIAogIHNlbGVjdChsYXN0X2NvbChvZmZzZXQgPSAyKTpsYXN0X2NvbCgpKSAlPiUgCiAgc2xpY2VfaGVhZChuID0gNCkKCmBgYAoKCkdyZWF0ISBUaGF0IGxvb2tzIGxpa2Ugd2UgZXhwZWN0ZWQuIFdlIGNhbiBzZWUgdGhhdCB0aGUgY29vcmRpbmF0ZSB2YWx1ZXMgYXJlIHNsaWdodGx5IGRpZmZlcmVudCBub3cuCgpgYGB7cn0Kb3JpZ2luYWxfc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSByZWFkX2NzdihoZXJlKCJwcm9jZXNzZWRfZGF0YSIsCiAgICAgICAgICAgICAgInNob290aW5nX2RhdGEuY3N2IikpCgpvcmlnaW5hbF9zaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JXNlbGVjdChsb25naXR1ZGUsIGxhdGl0dWRlKSAlPiUgc2xpY2VfaGVhZChuID0gNCkKYGBgCgoKCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQpzdHIoc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCkKCmBgYAoKIyMjIwoKTG9va3MgZ29vZCEKCk5vdyB3ZSB3aWxsIHNhdmUgb3VyIHdyYW5nbGVkIGRhdGEsIGFnYWluIHVzaW5nIGB3cml0ZV9jc3YoKWAuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQoKcmVhZHI6OndyaXRlX2NzdihzaG9vdGluZ19kYXRhLCBwYXRoID0gaGVyZSgicHJvY2Vzc2VkX2RhdGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YV9wcmVfZ2VvX3dyYW5nbGVkLmNzdiIpKQp3cml0ZV9jc3Yoc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCwgcGF0aCA9IGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNob290aW5nX2RhdGFfd3JhbmdsZWQuY3N2IikpCmBgYAoKCgpmcm9tIE1pY2hhZWw6CmBgYHtyLCBldmFsID0gRkFMU0V9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgPC0gcmVhZF9jc3YoaGVyZSgicHJvY2Vzc2VkX2RhdGEiLAogICAgICAgICAgICAgICJzaG9vdGluZ19kYXRhLmNzdiIpKQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgZmlsdGVyKCFpcy5uYShsb25naXR1ZGUpLAogICAgICAgICAhaXMubmEobGF0aXR1ZGUpKSAlPiUKICBzZjo6c3RfYXNfc2YoY29vcmRzID0gYygibG9uZ2l0dWRlIiwgImxhdGl0dWRlIiksIGNycyA9IDQzMjYpICU+JQogIAogIHN0X3RyYW5zZm9ybShjcnMgPSAxMDIwMDgpICU+JQogIHN0X2ppdHRlcihhbW91bnQgPSA1MCkgJT4lCiAgc3RfdHJhbnNmb3JtKGNycyA9IDQzMjYpICU+JQogIG11dGF0ZShsb25naXR1ZGUgPSBzdF9jb29yZGluYXRlcyguKVssMV0sCiAgICAgICAgIGxhdGl0dWRlID0gc3RfY29vcmRpbmF0ZXMoLilbLDJdKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1nZW9tZXRyeSkKCnN0YXRlX2RmIDwtIGFzX3RpYmJsZShjYmluZChzdGF0ZS5hYmIsIHN0YXRlLm5hbWUpKQoKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSkgJT4lCiAgbXV0YXRlKERhdGVfeWVhciA9IHllYXIoRGF0ZSkpICU+JQogIHJlbmFtZSgiU3RhdGVfYWJiIiA9IFN0YXRlKSAlPiUKICBsZWZ0X2pvaW4oc3RhdGVfZGYsIGJ5ID0gYygiU3RhdGVfYWJiIiA9ICJzdGF0ZS5hYmIiKSkgJT4lCiAgcmVuYW1lKCJTdGF0ZSIgPSBzdGF0ZS5uYW1lKSAlPiUKICBtdXRhdGUoU3RhdGUgPSBzdHJfdG9fdGl0bGUodG9sb3dlcihTdGF0ZSkpKSAlPiUKICBtdXRhdGUoYFN1aWNpZGUgKG9yIGF0dGVtcHRlZCBzdWljaWRlKSBieSBTaG9vdGVyIChZL04pYCA9IGNhc2Vfd2hlbihgU3VpY2lkZSAob3IgYXR0ZW1wdGVkIHN1aWNpZGUpIGJ5IFNob290ZXIgKFkvTilgID09ICJZZXMiIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKQoKc3RhcnQgPC0gMTk3MAplbmQgPC0gMjAyMAoKd3JpdGVfY3N2KHNob290aW5nX2RhdGFfZ2VvY29kZWQsIHBhdGggPSBoZXJlKCJwcm9jZXNzZWRfZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YV93cmFuZ2xlZC5jc3YiKSkKCnJtKHNob290aW5nX2RhdGFfZ2VvY29kZWQpCgpzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHJlYWRfY3N2KGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzaG9vdGluZ19kYXRhX3dyYW5nbGVkLmNzdiIpKQpgYGAKCgoKSU5UUk9EVUNFIFRIRSBDT05DRVBUIE9GIERBU0hCT0FSRFMKCklOVFJPRFVDRSBgZmxleGRhc2hib2FyZGAKCiMjICoqRGF0YSBBbmFseXNpcyBhbmQgVmlzdWFsaXphdGlvbioqCioqKiAKCkZpcnN0IGxldCdzIGxvYWQgdGhlIGRhdGEgYnkgcmVhZGluZyBpbiBvdXIgd3JhbmdsZWQgdmVyc2lvbiBvZiB0aGUgZGF0YS4KCmBgYHtyfQpzaG9vdGluZ19kYXRhIDwtIHJlYWRfY3N2KGhlcmUoInByb2Nlc3NlZF9kYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzaG9vdGluZ19kYXRhLmNzdiIpKQoKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSByZWFkX2NzdihoZXJlKCJwcm9jZXNzZWRfZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2hvb3RpbmdfZGF0YV93cmFuZ2xlZC5jc3YiKSkKYGBgCgoKVGhlcmUgYXJlIHNldmVyYWwgZWxlbWVudHMgd2Ugd291bGQgbGlrZSB0byBpbmNsdWRlIGluIG91ciBkYXNoYm9hcmQuIAoKT25lIHRoaW5nIHdlIHdvdWxkIGxpa2UgaXMgYW4gaW50ZXJhY3RpdmUgdGFibGUuCgpXZSBjYW4gZG9uZSBzbyB1c2luZyB0aGUgYGRhdGF0YWJsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYERUYCBwYWNrYWdlLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KRFQ6OmRhdGF0YWJsZShzaG9vdGluZ19kYXRhKQpgYGAKVGhpcyBjcmVhdGVzIGEgc2VhcmNoYWJsZSB0YWJsZSBhbmQgdGhlIG9yZGVyIGluIHdoaWNoIHRoZSBkYXRhIGlzIGRpc3BsYXllZCBjYW4gYmUgdG9nZ2xlZCB0byBjaGFuZ2UgZm9yIGVhY2ggdmFyaWFibGUuCgpIb3dldmVyLCB3ZSBoYXZlIG1hbnkgdmFyYWlibGVzLCBzbyB0aGlzIGdldCdzIHRvIGJlIG92ZXJ3aGVsbWluZy4gU2luY2UgdGhlcmUgYXJlIHNvIG1hbnkgdGhpcyBldmVuIG1vZGlmaWVzIHRoZSB3YXkgdGhlIHJtYXJrZG93biBmb3IgdGhpcyBjYXNlIHN0dWR5IGlzIHJlbmRlcmVkLCB0aHVzIGluc3RlYWQgb2YgZGlzcGxheWluZyBhbGwgb2YgdGhlIHZhcmlhYmxlcywgbGV0J3MgY2hvb3NlIG9ubHkgc29tZSBvZiB0aGUgbW9zdCBpbnRlcmVzdGluZyB0byBkaXNwbGF5IG9uIG91ciBkYXNoYm9hcmQuCgoKYGBge3J9CkRUX3RhYmxlIDwtIHNob290aW5nX2RhdGElPiUKICBkcGx5cjo6c2VsZWN0KERhdGUsCiAgICAgICAgICAgICAgICBTY2hvb2wsCiAgICAgICAgICAgICAgICBDaXR5LAogICAgICAgICAgICAgICAgU3RhdGUsCiAgICAgICAgICAgICAgICBgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWAsCiAgICAgICAgICAgICAgICBgTmFycmF0aXZlIChEZXRhaWxlZCBTdW1tYXJ5LyBCYWNrZ3JvdW5kKWApICU+JQogIHJlbmFtZSgiTmFycmF0aXZlIiA9IGBOYXJyYXRpdmUgKERldGFpbGVkIFN1bW1hcnkvIEJhY2tncm91bmQpYCkKCkRUOjpkYXRhdGFibGUoRFRfdGFibGUpCmBgYAoKCk5vdyB3ZSB3b3VsZCBhbHNvIGxpa2UgdG8gbWFrZSBzb21lIHZpc3VhbGl6YXRpb25zIG9mIG91ciBkYXRhLgoKIyMjIFllYXJseSBEZWF0aHMKCkZpcnN0LCB3ZSB3b3VsZCBsaWtlIHRvIGNyZWF0ZSBhIHBsb3Qgb2YgdGhlIG51bWJlciBvZiBzaG9vdGluZ3MgcGVyIHllYXIuCgpUbyBkbyB0aGlzIHdlIHdpbGwgZmlyc3QgY291bnQgdGhlIG51bWJlciBvZiBzaG9vdGluZ3MgcGVyIHllYXIgYnkgdXNpbmcgdGhlIGBncm91cF9ieSgpYCBmdW5jdGlvbiAgYW5kIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gVGhlIGBncm91cF9ieSgpYCBmdW5jdGlvbnMgYWxsb3dzIHVzIHRvIHN1bW1hcml6ZSB0aGUgZGF0YSBhY3Jvc3Mgc3BlY2lmaWMgZ3JvdXBzIHNwZWNpZmllZCBieSBhIHZhcmlhYmxlIG9yIG11bHRpcGxlIHZhcmlhYmxlcy4gQnkgZ3JvdXBpbmcgYnkgYERhdGVfeWVhcmAgd2UgY2FuIHRoZW4gdXNlIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gdG8gY291bnQgdGhlIG51bWJlciBvZiByb3dzIHdpdGggc2hvb3RpbmcgZXZlbnQgaW5mb3JtYXRpb24gCmZvciBlYWNoIHVuaXF1ZSB2YWx1ZSBvZiB0aGUgYERhdGVfeWVhcmAgdmFyaWFibGUuCgpXZSB0aGVuIHdhbnQgdG8gdXNlIHRoZSBgdW5ncm91cCgpYCBmdW5jdGlvbiB0byBnZXQgdGhlIGRhdGEgb3V0IG9mIHRoaXMgZ3JvdXBpbmcgYmFzZWQgb24gdGhlIGBEYXRhX3llYXJgIHZhcmFpYmxlLgoKCmBgYHtyfQoKc2hvb3RpbmdfcGVyX3llYXI8LSBzaG9vdGluZ19kYXRhICU+JQogICAgICAgbXV0YXRlKERhdGUgPSBsdWJyaWRhdGU6Om1keShEYXRlKSkgJT4lCiAgbXV0YXRlKERhdGVfeWVhciA9IGx1YnJpZGF0ZTo6eWVhcihEYXRlKSkgJT4lCiAgICBncm91cF9ieShEYXRlX3llYXIpICU+JQogICAgY291bnQoKSAlPiUKICAgIHVuZ3JvdXAoKQoKCnNob290aW5nX3Blcl95ZWFyCgpgYGAKTmljZSBsb29rcyBnb29kIQoKTm93IHRvIG1ha2UgYSBwbG90IG9mIHRoaXMgZGF0YSB3ZSB3aWxsIHVzZSB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgo8ZGV0YWlscz48c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgYW4gaW50cm9kdWN0aW9uIGFib3V0IHRoaXMgcGFja2FnZSBpZiB5b3UgYXJlICBuZXcgdG8gdXNpbmcgYGdncGxvdDJgIDwvc3VtbWFyeT4KClRoZSBbZ2dwbG90MiBwYWNrYWdlXShodHRwOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKSBpcyBnZW5lcmFsbHkgaW50dWl0aXZlIGZvciBiZWdpbm5lcnMgYmVjYXVzZSBpdCBpcyBiYXNlZCBvbiBhICBbZ3JhbW1hciBvZiBncmFwaGljc10oaHR0cDovL3ZpdGEuaGFkLmNvLm56L3BhcGVycy9sYXllcmVkLWdyYW1tYXIuaHRtbCkgb3IgdGhlIGBnZ2AgaW4gYGdncGxvdDJgLiAKVGhlIGlkZWEgaXMgdGhhdCB5b3UgY2FuIGNvbnN0cnVjdCBtYW55IHNlbnRlbmNlcyBieSBsZWFybmluZyBqdXN0IGEgZmV3IG5vdW5zLCBhZGplY3RpdmVzLCBhbmQgdmVyYnMuIFRoZXJlIGFyZSBzcGVjaWZpYyDigJx3b3Jkc+KAnSB0aGF0IHdlIHdpbGwgbmVlZCB0byBsZWFybiBhbmQgb25jZSB3ZSBkbywgeW91IHdpbGwgYmUgYWJsZSB0byBjcmVhdGUgKG9yIOKAnHdyaXRl4oCdKSBodW5kcmVkcyBvZiBkaWZmZXJlbnQgcGxvdHMuCgpUaGUgY3JpdGljYWwgcGFydCB0byBtYWtpbmcgZ3JhcGhpY3MgdXNpbmcgYGdncGxvdDJgIGlzIHRoZSBkYXRhIG5lZWRzIHRvIGJlIGluIGEgX3RpZHlfIGZvcm1hdC4gCkdpdmVuIHRoYXQgd2UgaGF2ZSBqdXN0IHNwZW50IHRpbWUgcHV0dGluZyBvdXIgZGF0YSBpbiBfdGlkeV8gZm9ybWF0LCB3ZSBhcmUgcHJpbWVkIHRvIHRha2UgYWR2YW50YWdlIG9mIGFsbCB0aGF0IGBnZ3Bsb3QyYCBoYXMgdG8gb2ZmZXIhIAoKV2Ugd2lsbCBzaG93IGhvdyBpdCBpcyBlYXN5IHRvIHBpcGUgX3RpZHlfIGRhdGEgKG91dHB1dCkgYXMgaW5wdXQgdG8gb3RoZXIgZnVuY3Rpb25zIHRoYXQgY3JlYXRlIHBsb3RzLiAKVGhpcyBhbGwgd29ya3MgYmVjYXVzZSB3ZSBhcmUgd29ya2luZyAKd2l0aGluIHRoZSBfdGlkeXZlcnNlXy4gCgoqKldoYXQgaXMgdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24/KiogCkFzIGV4cGxhaW5lZCBieSBIYWRsZXkgV2lja2hhbToKCj4gVGhlIGdyYW1tYXIgdGVsbHMgdXMgdGhhdCBhIHN0YXRpc3RpY2FsIGdyYXBoaWMgaXMgYSBtYXBwaW5nIGZyb20gZGF0YSB0byBhZXN0aGV0aWMgYXR0cmlidXRlcyAoY29sb3VyLCBzaGFwZSwgc2l6ZSkgb2YgZ2VvbWV0cmljIG9iamVjdHMgKHBvaW50cywgbGluZXMsIGJhcnMpLiBUaGUgcGxvdCBtYXkgYWxzbyBjb250YWluIHN0YXRpc3RpY2FsIHRyYW5zZm9ybWF0aW9ucyBvZiB0aGUgZGF0YSBhbmQgaXMgZHJhd24gb24gYSBzcGVjaWZpYyBjb29yZGluYXRlcyBzeXN0ZW0uCgpgZ2dwbG90MmAgVGVybWlub2xvZ3k6IAoKLSAqKmdncGxvdCoqIC0gdGhlIG1haW4gZnVuY3Rpb24gd2hlcmUgeW91IHNwZWNpZnkgdGhlIGRhdGFzZXQgYW5kIHZhcmlhYmxlcyB0byBwbG90ICh0aGlzIGlzIHdoZXJlIHdlIGRlZmluZSB0aGUgYHhgIGFuZApgeWAgdmFyaWFibGUgbmFtZXMpCi0gKipnZW9tcyoqIC0gZ2VvbWV0cmljIG9iamVjdHMKICAgIC0gZS5nLiBgZ2VvbV9wb2ludCgpYCwgYGdlb21fYmFyKClgLCBgZ2VvbV9saW5lKClgLCBgZ2VvbV9oaXN0b2dyYW0oKWAKLSAqKmFlcyoqIC0gYWVzdGhldGljcwogICAgLSBzaGFwZSwgdHJhbnNwYXJlbmN5LCBjb2xvciwgZmlsbCwgbGluZSB0eXBlcwotICoqc2NhbGVzKiogLSBkZWZpbmUgaG93IHlvdXIgZGF0YSB3aWxsIGJlIHBsb3R0ZWQKICAgIC0gY29udGludW91cywgZGlzY3JldGUsIGxvZywgZXRjCgpUaGUgZnVuY3Rpb24gYGFlcygpYCBpcyBhbiBhZXN0aGV0aWMgbWFwcGluZyBmdW5jdGlvbiBpbnNpZGUgdGhlIGBnZ3Bsb3QoKWAgb2JqZWN0LiAKV2UgdXNlIHRoaXMgZnVuY3Rpb24gdG8gc3BlY2lmeSBwbG90IGF0dHJpYnV0ZXMgKGUuZy4gYHhgIGFuZCBgeWAgdmFyaWFibGUgbmFtZXMpIHRoYXQgd2lsbCBub3QgY2hhbmdlIGFzIHdlIGFkZCBtb3JlIGxheWVycy4gIAoKQW55dGhpbmcgdGhhdCBnb2VzIGluIHRoZSBgZ2dwbG90KClgIG9iamVjdCBiZWNvbWVzIGEgZ2xvYmFsIHNldHRpbmcuIApGcm9tIHRoZXJlLCB3ZSB1c2UgdGhlIGBnZW9tYCBvYmplY3RzIHRvIGFkZCBtb3JlIGxheWVycyB0byB0aGUgYmFzZSBgZ2dwbG90KClgIG9iamVjdC4gClRoZXNlIHdpbGwgZGVmaW5lIHdoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gaWxsdXN0cmF0aW5nIHVzaW5nIHRoZSBkYXRhLgoKKioqCjwvZGV0YWlscz4KCkZvciBtb3JlIG9mIGFuIGludHJvZHVjdGlvbiBvbiBjcmVhdGluZyBwbG90cyB3aXRoIGBnZ3Bsb3QyYCAsIHNlZSB0aGlzIFtjYXNlIHN0dWR5XSgpCgpGaXJzdCwgd2Ugc3RhcnQgd2l0aCB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgpUaGlzIGZ1bmN0aW9uIHJlcXVpcmVzIHRoYXQgdGhlIGFlc3RoZXRpY3MgYGFlcygpYCBiZSBzcGVjaWZpZWQuIFRoaXMgaW52b2x2ZXMgY2hvb3Npbmcgd2hhdCB2YXJpYWJsZSB3aWxsIGJlIHBsb3R0ZWQgb24gdGhlIHgtYXhpcyBhbmQgdGhlIHkgYXhpcy4gCgpUaGlzIHdpbGwgY3JlYXRlIGFuIGVtcHR5IHBsb3QgYXJlYSwgbmV4dCB3ZSBuZWVkIHRvIHVzZSBvbmUgb2YgdGhlIGBnZW9tKmAgZnVuY3Rpb25zIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB0byBzcGVjaWZ5IHdoYXQgdHlwZSBvZiBwbG90IHdlIHdhbnQgdG8gY3JlYXRlLgoKVHlwZSBnZW9tIGludG8gdGhlIFJTdHVkaW8gY29uc29sZSBhbmQgeW91IHdpbGwgc2VlIG1hbnkgb3B0aW9ucyB0byBzY3JvbGwgdGhyb3VnaC4KCldlIHdpbGwgYmUgY3JlYXRpbmcgYSBgZ2VvbV9jb2woKWAgcGxvdCwgd2hpY2ggaXMgYSBwYXJ0aWN1bGFyIHR5cGUgb2YgYmFyIHBsb3QgdGhhdCB1c2VzIHRoZSBhY3V0YWwgdmFsdWVzIHRvIHBsb3QsIHJhdGhlciB0aGFuIGNvdW50cywgd2hpY2ggaXMgdGhlIGRlZmF1bHQgb2YgYGdlb21fYmFyKClgIFdlIHdpbGwgc3BlY2lmeSB3aXRoIHRoZSBgZmlsbGAgYXJndW1lbnQsIHRoYXQgd2Ugd2FudCBvdXIgYmFycyB0byBiZSBmaWxsZWQgd2l0aCB0aGUgY29sb3IgYmxhY2suCgpXZSB3aWxsIGFsc28gbW9kaWZ5IHRoZSB4LWF4aXMgdXNpbmcgdGhlIGBzY2FsZV94X2NvbnRpbnVvdXMoKWAgZnVuY3Rpb24uIFRoaXMgZnVuY3Rpb24gYWxsb3dzIGZvciBzcGVjaWZpY2F0aW9uIG9mIHRoZSByYW5nZSBvciBsaW1pdHMgb2YgdGhlIGF4aXMgdXNpbmcgdGhlIGBsaW1pdHNgIGFyZ3VtZW50LiBXZSBjYW4gdXNlIHRoZSBiYXNlIGBzZXEoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGEgc2VxdWVuY2Ugb2YgbnVtYmVycyBmb3IgZWFjaCB0aWNrIG1hcmsuCgoKV2UgY2FuIGFkZCBsYWJlbHMgdG8gb3VyIHBsb3QgdXNpbmcgdGhlIGBsYWJzKClgIGZ1bmN0aW9uIG9mIGBnZ3Bsb3QyYC4gVGhpcyBoYXMgYXJndW1lbnRzIHN1Y2ggYXMgYHhgIGFuZCBgeWAgZm9yIHRoZSBheGVzIGFuZCBgdGl0bGVgIGFuZCBgc3VidGl0bGVgIGZvciB0aXRsZXMuCgpXZSB3aWxsIGFsc28gbW9kaWZ5IHRoZSBvdmVyYWxsIGFlc3RoZXRpY3Mgb2YgdGhlIHBsb3QgdXNpbmcgYSBgdGhlbWVfKmAgZnVuY3Rpb24uIFNlZSBbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dndGhlbWUuaHRtbCkgZm9yIGEgbGlzdCBvZiBvcHRpb25zLgoKYGBge3J9CnN0YXJ0IDwtIDE5NzAKZW5kIDwtIDIwMjAKCgpzaG9vdGluZ19wZXJfeWVhciAlPiUKICAgIGdncGxvdChhZXMoeCA9IERhdGVfeWVhciwgeSA9IG4pKSArCiAgICBnZW9tX2NvbCggZmlsbCA9ICJibGFjayIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKHN0YXJ0LTEsIGVuZCsxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAiWWVhcmx5IERlYXRocyBBdHRyaWJ1dGFibGUgdG8gU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHN1YnRpdGxlID0gIlVuaXRlZCBTdGF0ZXMiLAogICAgICAgICB4ID0gIlNjaG9vbCBTaG9vdGluZ3MiLAogICAgICAgICB5ID0gIiIpCmBgYAoKIyMjIFllYXJseSBDdW11bGF0aXZlIERlYXRocwoKTm93IGxldCdzIG1ha2UgYW5vdGhlciBwbG90IG9mIHRoZSBjdW11bGF0aXZlIGRlYXRocyBlYWNoIHllYXIgaW5jbHVkaW5nIHRob3NlIG9mIHRoZSBwcmV2aW91cyB5ZWFycy4gSW4gdGhpcyBjYXNlIHdlIGNhbiB1c2UgdGhlIGBzaG9vdGluZ19wZXJfeWVhcmAgb2JqZWN0IHRoYXQgd2UgcHJldmlvdXNseSBtYWRlLiBXZSB3YW50IHRvIGFkZCBhIG5ldyB2YXJpYWJsZSB1c2luZyB0aGUgYG11dGF0ZWAgZnVuY3Rpb24gY2FsbGVkIGBuX2N1bV9zdW1gIGJ5IHVzaW5nIHRoZSBgY3Vtc3VtKClgIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBhIGN1bXVsYXRpdmUgc3VtIGJhc2VkIG9uIHRoZSB5ZWFybHkgY291bnQuIAoKYGBge3J9CgpzaG9vdGluZ19wZXJfeWVhcgoKc2hvb3RpbmdfcGVyX3llYXJfY3VtIDwtIHNob290aW5nX3Blcl95ZWFyJT4lCiAgICBtdXRhdGUobl9jdW1zdW0gPSBjdW1zdW0obikpCgpzaG9vdGluZ19wZXJfeWVhcl9jdW0gCgpgYGAKCkdyZWF0LCB0aGlzIGxvb2tzIGxpa2Ugd2Ugd291bGQgZXhwZWN0IQoKTm93IGxldCdzIG1ha2UgYSBwbG90IGxpa2Ugd2UgZGlkIGJlZm9yZToKCmBgYHtyfQoKc2hvb3RpbmdfcGVyX3llYXJfY3VtICU+JQogICAgZ2dwbG90KGFlcyh4ID0gRGF0ZV95ZWFyLCB5ID0gbl9jdW1zdW0pKSArCiAgICBnZW9tX2NvbChmaWxsID0gImJsYWNrIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShzdGFydCwgZW5kLCBieSA9IDUpLAogICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcShzdGFydCwgZW5kLCBieSA9IDUpLAogICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoc3RhcnQtMSwgZW5kKzEpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgbGFicyh0aXRsZSA9ICJZZWFybHkgQ3VtdWxhdGl2ZSBEZWF0aHMgQXR0cmlidXRhYmxlIHRvIFNjaG9vbCBTaG9vdGluZ3MiLAogICAgICAgICBzdWJ0aXRsZSA9ICJVbml0ZWQgU3RhdGVzIiwKICAgICAgICAgeCA9ICJTY2hvb2wgU2hvb3RpbmdzIiwKICAgICAgICAgeSA9ICIiKQpgYGAKCiMjIyBEZWF0aHMgcGVyIFNob290aW5nCgpOb3csIGxldHMgbWFrZSBhIHBsb3Qgb2YgdGhlIG51bWJlciBvZiBkZWF0aHMgcGVyIHNob290aW5nIGJhc2VkIG9uIHRoZSBgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWAgdmFyYWlibGUuIE91ciBmaXJzdCBwbG90IGNvdWxkIGFsc28gaGF2ZSBiZWVuIG1hZGUgdXNpbmcgYGdlb21fYmFyKClgIGluc3RlYWQgb2YgYGdlb21fY29sKClgIHRoaXMgbWFrZXMgYSBzaW1pbGFyIHBsb3QgYnV0IGF1dG9tYXRpY2FsbHkgdXNlcyB0aGUgY291bnQgZm9yIG9uZSBvZiB0aGUgYXhlcy4gCgpgYGB7cn0KIyBUaGlzIGlzIGVxdWl2YWxlbnQ6CiMgZGVhdGhzX3Blcl9ldmVudCA8LSBzaG9vdGluZ19kYXRhICU+JQojICAgICBncm91cF9ieShgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWApICU+JQojICAgICBjb3VudCgpICU+JQojICAgICB1bmdyb3VwKCkKIyAKIyBkZWF0aHNfcGVyX2V2ZW50ICU+JQojICAgICBnZ3Bsb3QoYWVzKHkgPSBgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWAsIHggPSBuKSkgKwojICAgICBnZW9tX2NvbChmaWxsID0gImJsYWNrIikrCiMgICAgIHRoZW1lX21pbmltYWwoKSArCiMgICAgIGxhYnModGl0bGUgPSAiRGVhdGhzIHBlciBTY2hvb2wgU2hvb3RpbmciLAojICAgICAgICAgIHN1YnRpdGxlID0gIlVuaXRlZCBTdGF0ZXMiLAojICAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiMgICAgICAgICAgeSA9ICIiKQoKc2hvb3RpbmdfZGF0YSAlPiUKICAgIGdncGxvdChhZXMoeCA9IGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCkpICsKICAgIGdlb21fYmFyKGZpbGwgPSAiYmxhY2siKSArCiAgIyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAsIGJ5ID0gMSksCiAgIyAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsMTAsIGJ5ID0gMSksCiAgIyAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMSwxMCkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gIkRlYXRocyBwZXIgU2Nob29sIFNob290aW5nIiwKICAgICAgICAgc3VidGl0bGUgPSAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHkgPSAiIikKCmBgYApJdCBpcyBhIGJpdCBkaWZmaWN1bHQgdG8gc2VlIHRoZSBzaG9vdGluZ3MgdGhhdCBoYWQgbW9yZSBudW1lcmlvdXMgZGVhdGhzLCBzbyB3ZSB3aWxsIGFkZCBhIGZhY2V0IHRoYXQgem9vbXMgaW4gb24gdGhpcyBwb3J0aW9uIG9mIHRoZSBwbG90LiBXZSBjYW4gZG8gc28sIHVzaW5nIHRoZSBgZmFjZXRfem9vbSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdnZm9yY2VgIHBhY2thZ2UuCgpgYGB7cn0KbGlicmFyeShnZ2ZvcmNlKQoKCnNob290aW5nX2RhdGEgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWApKSArCiAgICBnZW9tX2JhcihmaWxsID0gImJsYWNrIikgKwogICMgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEwLCBieSA9IDEpLAogICMgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDEwLCBieSA9IDEpLAogICMgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTEsMTApKSArCmdnZm9yY2U6OmZhY2V0X3pvb20oeGxpbSA9IGMoMTAsIG1heChwdWxsKHNob290aW5nX2RhdGEsIGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCkpKSkrCnRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gIkRlYXRocyBwZXIgU2Nob29sIFNob290aW5nIiwKICAgICAgICAgc3VidGl0bGUgPSAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHkgPSAiIikKYGBgCgpgYGB7cn0KCnNob290aW5nX2RhdGEgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWApKSArCiAgICBnZW9tX2ZyZXFwb2x5KCkKYGBgCgpgYGB7cn0KZGVhdGhzX3BlcmNfZXZlbnQgPC1zaG9vdGluZ19kYXRhICU+JQogICBjb3VudChgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWApICU+JQogIHJlbmFtZSgibnVtX2V2ZW50cyI9IG4pICU+JQogICBtdXRhdGUocGVyY2VudCA9IChudW1fZXZlbnRzL3N1bShudW1fZXZlbnRzKSoxMDApKQoKZ3JlYXRlcl90aGFuNDwtZGVhdGhzX3BlcmNfZXZlbnQgJT4lIGZpbHRlcihgS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWAgPj00KSAlPiUgY29sU3VtcygpCmdyZWF0ZXJfdGhhbjQKCmRlYXRoc19wZXJjX2V2ZW50ICU8PiUgIGJpbmRfcm93cyhncmVhdGVyX3RoYW40KSAlPiUgbXV0YXRlKGNhdGVnb3J5ID0gcGFzdGUoYEtpbGxlZCAoaW5jbHVkZXMgc2hvb3RlcilgLCAiZGVhdGhzIikpIAoKbGFzdChwdWxsKGRlYXRoc19wZXJjX2V2ZW50LCBjYXRlZ29yeSkpCgojIGRlYXRoc19wZXJjX2V2ZW50ICU8PiUgbXV0YXRlKGNhdGVnb3J5PSByZWNvZGUoY2F0ZWdvcnksICI4NSBkZWF0aHMiID0gIjQrZGVhdGhzIikpCgpkZWF0aHNfcGVyY19ldmVudCAlPD4lIG11dGF0ZShjYXRlZ29yeT0gY2FzZV93aGVuKGNhdGVnb3J5ID09ICBsYXN0KHB1bGwoZGVhdGhzX3BlcmNfZXZlbnQsIGNhdGVnb3J5KSkgfiAiNCtkZWF0aHMiLCBUUlVFIH5jYXRlZ29yeSApKQoKbGlicmFyeSh3YWZmbGUpCgpkZWF0aHNfcGVyY19ldmVudCAlPiUgc2VsZWN0KC1gS2lsbGVkIChpbmNsdWRlcyBzaG9vdGVyKWApICU+JQogIGZpbHRlcihwZXJjZW50Pi41KSAlPiUKICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKHBlcmNlbnQpKSAlPiUKICBzZWxlY3QoLW51bV9ldmVudHMpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSBwZXJjZW50KSAlPiUKICB3YWZmbGUoIGNvbG9ycyA9IGMoImdyZXk1NCIsICJibGFjayIsICJyZWQiLCJncmV5NzciLCAiIzAwOWJkYSIgKSwKICAgICAgICAgIGxlZ2VuZF9wb3MgPSAiYm90dG9tIikKCgoKZGVhdGhzX3BlcmNfZXZlbnQgJT4lCiAgZmlsdGVyKHBlcmNlbnQ+MC41KSAlPiUKICAgIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gcGVyY2VudCwgZmlsbCA9IGNhdGVnb3J5KSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIikgKwogICAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz0gTlVMTCkrCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKQoKYGBgCgoKCmF2b2NhZG8hIGNvbHVtYmluZSAtIHdoaWNoIGhhZCAxMiBkZWF0aHMgaXMgbm90IGluY2x1ZGVkLi4uCgphbHNvIGJldHRlciB0byBwbG90IGRpZmZlcmVudGx5IHRvIHNob3cgaGlnaCB2YWx1ZXMgLSBtYXliZSBhIHpvb20KCiMjICoqRGFzaGJvYXJkKioKKioqCgpgYGB7cn0KRFQ6OmRhdGF0YWJsZShzaG9vdGluZ19kYXRhX2dlb2NvZGVkKQpgYGAKCmBgYHtyfQpEVDo6ZGF0YXRhYmxlKHNob290aW5nX2RhdGEpCmBgYAoKCiMjIFJBIE5PVEVTCgojIyMgR2VuZXJhbCBOb3RlcwoKQ29uc3VsdCB0aGlzIGRvY3VtZW50IGZvciBhIGdlbmVyYWwgb3ZlcnZpZXc6CgorIGNhc2Utc3R1ZHktc3RydWN0dXJlLU1PLW5vdGVzCgpUaGVyZSBhcmUgc2V2ZXJhbCBkYXRhc2V0cyBpbnZvbHZlZCBpbiB0aGlzIGNhc2Ugc3R1ZHkKCisgUmF3IGRhdGFzZXQgKHJhd19kYXRhL0stMTIgU1NEQiAoUHVibGljKSAtIEstMTIgU1NEQiAoUHVibGljKSBMaW5rZWQuY3N2KQorIEdlb2NvZGVkIGRhdGFzZXQgIChwcm9jZXNzZWRfZGF0YS9zaG9vdGluZ19kYXRhLmNzdikKKyBXcmFuZ2xlZCBkYXRhc2V0IChwcm9jZXNzZWRfZGF0YS9zaG9vdGluZ19kYXRhX3dyYW5nbGVkKQoKVGhpcyBkb2N1bWVudCB1c2VzIHRoZSBnZW9jb2RlZCBkYXRhc2V0IHRvIHByb2R1Y2UgdGhlIHdyYW5nbGVkIGRhdGFzZXQuCgpUaGUgd3JhbmdsZWQgZGF0YXNldCBpcyB0aGVuIHVzZWQgdG8gcHJvZHVjZSB0aGUgZGFzaGJvYXJkIGluIHRoZSBvdGhlciBkb2N1bWVudC4KCkNvZGUgdG8gZ2VvY29kZSBhbmQgdGhlbiB3cmFuZ2xlIHRoZSBkYXRhc2V0cyBhcmUgaW5jbHVkZWQgaW4gdGhpcyBkb2N1bWVudC4KClRoZSBnb2Vjb2RpbmcgcmVxdWlyZWQgdG8gcHJvZHVjZSB0aGlzIGNhc2Ugc3R1ZHkgdG9vayBhcHByb3hpbWF0ZWx5IDEuNS0yIGhvdXJzIG9uIGEgTWFjYm9vayBBaXIgKDIwMTUpLiAKClRoZSBtYXBzIHdlIGNyZWF0ZWQgd2VyZSBsYXJnZWx5IHJlc3RyaWN0cmVkIHRvIGVmZmljaWVudCBtYXBzLiBNYXBzIHdpdGggbXVsdGlwbGUgbGF5ZXJzIHJlcXVpcmVkIGEgbG90IG9mIGNvbXB1dGF0aW9uYWwgcG93ZXIgd2hpY2ggd2UgY2hvc2Ugbm90IHRvIHVzZS4gCgojIyMgSW1wb3J0YW50IExpbmtzCgpbUlN0dWRpby9mbGV4ZGFzaGJvYXJkXShodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9mbGV4ZGFzaGJvYXJkLykKCltMZWFmbGV0XShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvKQoKIyMjIE1ldGFkZXRhCgpGbGV4ZGFzaGJvYXJkIHJlcXVpcmVzIG1ldGFkZXRhIHRvIHdvcmsuIEEgZ29vZCBleGFtcGxlIG9mIHdoYXQgd2UgZGlkIGNhbiBiZSBmb3VuZCBvbiB0aGUgbGF5b3V0IHNlY3Rpb24gb2YgdGhlIGBSU3R1ZGlvL2ZsZXhkYXNoYm9hcmQvSG9tZWAgbGluayBpbmNsdWRlZCBhYm92ZS4gCgojIyMgQ29sdW1ucyAmIFJvd3MKCkluIHRoZSBtZXRhZGF0YSwgd2Ugc3BlY2lmeSB3aGV0aGVyIHdlIHdhbnQgb3VyIG91dHB1dCB0byBiZSBvcmllbnRlZCBpbiByb3dzIChsZWZ0IHRvIHJpZ2h0KSBvciBjb2x1bW5zICh0b3AgdG8gYm90dG9tKS4gSWYgSSBjcmVhdGVkIHR3byBwbG90cyB3aXRoIGNvbHVtbndpc2Ugc2V0dGluZ3MsIHRoZSBmaXJzdCBwbG90IHdpbGwgYmUgYXQgdGhlIHRvcCBhbmQgdGhlIHNlY29uZCBhdCB0aGUgYm90dG9tLiBJZiBJIGRvIHRoZSBzYW1lIHRoaW5nIGZvciByb3d3aXNlIHNldHRpZ25zLCB0aGUgZmlyc3QgcGxvdCB3aWxsIGJlIG9uIHRoZSBsZWZ0IGFuZCB0aGUgc2Vjb25kIHBsb3Qgd2lsbCBiZSBvbiB0aGUgcmlnaHQuIEVhY2ggdGltZSB3ZSBzcGVjaWZ5IGEgbmV3IGNvbHVtbiBvciByb3csIHRoZSBvdXRwdXQgaXMgc2hvd24gaW4gdGhpcyB3YXkgaW4gYSBzcGVjaWZpYyBjb2x1bW4vcm93LiBTZWUgYE11bHRpcGxlIENvbHVtbnNgIGFuZCBgUm93IE9yaWVudGF0aW9uYCBvbiB0aGUgYFJTdHVkaW8vZmxleGRhc2hib2FyZC9Ib21lYCBsaW5rIGluY2x1ZGVkIGFib3ZlIGZvciBhbiBleGFtcGxlLiAKCldlIHNwZWNpZnkgYSBjb2x1bW4vcm93IHdpdGggdGhpcy4KCmBgYAotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYAoKSXQgZG9lcyBub3QgbWF0dGVyIHdoZXRoZXIgeW91IHdyaXRlIGNvbHVtbi9yb3cgYWJvdmUgdGhhdC4gVGhlIG9ubHkgdGhpbmcgdGhhdCBtYXR0ZXJzIGlzIHRoZSBvcmllbnRhdGlvbiBzZXQtdXAgaW4gdGhlIG1ldGFkZXRhLiAKCm9yaWVudGF0aW9uOiBjb2x1bW5zIGlzIHRoZSBkZWZhdWx0IGZyb20gbXkgdW5kZXJzdGFuZGluZy4KCllvdSBuZWVkIHRvIHNwZWNpZnkgb3JpZW50YXRpb246IHJvd3MgaWYgeW91IHdhbnQgcm93d2lzZSBvcmllbnRhdGlvbgoKWW91IGNhbiBhZGQgdGFic2V0cyB0byBjb2x1bW5zL3Jvd3Mgd2l0aDogCgpgYGAKQ29sdW1uIHsudGFic2V0fQpgYGAKClNlZSB0aGUgVGFic2V0cyBzZWN0aW9uIG9uIGBSU3R1ZGlvL2ZsZXhkYXNoYm9hcmQvVXNpbmdgIGZvciBjbGVhciBleGFtcGxlcyBvZiBob3cgdGhpcyBjYW4gYmUgZG9uZS4KCiMjIyBHcmFwaGljcyAmIFRpdGxlcwoKTW9zdCBwbG90cyBjYW4gYmUgcGxvdHRlZCBieSBzcGVjaWZ5aW5nIGEgdGl0bGUgY2h1bmsgd2l0aCB0aGUgdGl0bGUgc3BlY2lmaWVkLgoKIyMjIFNoaW55CgpTaGlueSBjYW4gYmUgdXNlZCB3aXRoIGBmbGV4ZGFzaGJvYXJkYC4gQ29kaW5nIHdpdGggcGFja2FnZXMgdGhhdCBoYXZlIHNoaW55IGZ1bmN0aW9uYWxpdHkgcmVxdWlyZXMgc2hpbnktc3BlY2lmaWMgY29kZSBpcyBzaGlueSBpcyBlbmFibGVkLiBJbiBvdXIgY2FzZSwgc2hpbnkgaXMgZW5hYmxlZC4gUGFja2FnZXMgc3VjaCBhcyBgRFRgIG9yIGBMZWFmbGV0YCBtYXkgb3BlcmF0ZSBkaWZmZXJlbnRseSBhcyBhIHJlc3VsdC4gCgojIyMgTGVhZmxldAoKYExlYWZsZXRgIHdpZGdldHMgY2FuIGJlIGluY2x1ZGVkIHdpdGhpbiBkYXNoYm9hcmRzIGNyZWF0ZWQgd2l0aCBgZmxleGRhc2hib2FyZGAuCgpgTGVhZmxldGAgd29ya3MgYnkgcHJvdmlkZWQgYnkgYWRkaW5nIGJhc2UgZGF0YSAoc3VjaCBhcyBhIG1hcCkgYW5kIHRoZW4gYWRkaW5nIG1hcmtlcnMgaWYgZGVzaXJlZCBpbiBsYXllcnMuIFRoaXMgaXMgdmVyeSBzaW1pbGFyIHRvIGhvdyBgZ2dwbG90YCBmdW5jdGlvbnMgKHB1biBpbnRlbmRlZCkuCgpUaGUgbGF5ZXJzIGRpc3BsYXllZCBjYW4gYmUgY29udHJvbGxlZCB1c2luZyBhIHNvcnQgb2YgbGVnZW5kLiBEZXBlbmRpbmcgb24gdGhlIHR5cGUgb2YgbGF5ZXJzLCBzb21lIGluZm9ybWF0aW9uIG1heSBiZSBkaXNwbGF5ZWQgbXV0dWFsbHkgZXhjbHVzaXZlIG9mIHRoZSBvdGhlciBsYXllcnM7IG90aGVyIGxheWVycyAoc3VjaCBhcyBjaXJjbGVzL2dlbmVyYWwgbWFya2VycykgY2FuIGJlIHRvZ2dsZWQgb24gYW5kIG9mZi4gCgpBIG1pbmltYXAgY2FuIGJlIGFkZGVkLgoKVGhlIGxheWVycyBkaXNwbGF5ZWQgd2hlbiB0aGUgd2lkZ2V0IGlzIGZpcnN0IG9wZW5lZCBjYW4gYWxzbyBiZSBjb250cm9sbGVkLiBXZSBkaWQgdGhhdCBpbiB0aGlzIGNhc2Ugc3R1ZHkuIAoKYGdyb3Vwc2AgaW4gbGVhZmxldCBjYW4gYmUgdGhvdWdodCBvZiBhcyBsYXllci1zcGVjaWZpYyBJRHMgdGhhdCBjcmVhdGUgbGFiZWxzIGZvciBsZWdlbmRzIGFuZCBhbGxvdyBzcGVjaWZpYyBsYXllcnMgdG8gYmUgcmVmZXJyZWQgdG8gaW4gc2VwYXJhdGUgZnVuY3Rpb25zLiAKCklmIHdlIGNhbGxlZCBhIGdyb3VwICJMYXllciAxIiBhbmQgdGhlbiBpbiBhIHN1YnNlcXVlbnQgbGF5ZXIgcmVmZXJyZWQgdG8gIkxheWVyIDEiLCBgTGVhZmxldGAgd2lsbCBjb3JyZWN0bHkgaWRlbnRpZnkgd2hpY2ggbGF5ZXIgaXMgYmVpbmcgcmVmZXJlbmNlZC4KCmBMZWFmbGV0YCBjYW4gcmVxdWlyZSBhIGxvdCBvZiBjb21wdXRhdGlvbmFsIHBvd2VyOyB0aGlzIGNhbiBoYXZlIGFuIGltcGFjdCBvbiB0aGUgdHlwZXMgb2YgbWFwcyBwcm9kdWNlZC4KCkNsdXN0ZXJpbmcgb3B0aW9ucyBjYW4gYmUgYXBwbGllZCB0byBjaXJjbGVzL21hcmtlcnMuIFNvbWUgZXhhbXBsZXMgb2YgdGhpcyBjYW4gYmUgZm91bmQgb24gdGhlIGJvdHRvbSBvZiBbdGhpcyBwYWdlXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvbWFya2Vycy5odG1sKS4KCmBgYAojIyMgU3BlY2lmaWVkIFRpdGxlCmBgYAoKSWYgdGhlIHRpdGxlIGlzIHVuc3BlY2lmaWVkLi4uCgpgYGAKIyMjCmBgYAoKdGhlIGdyYXBoaWNzIHdpbGwgYmUgcmVjb2duaXplZCBidXQgbm8gdGl0bGUgd2lsbCBiZSBzaG93biBmb3IgdGhhdCBwYXJ0aWN1bGFyIGdyYXBoaWMuCgpgZmlnLXdpZHRoYCBhbmQgYGZpZy5oZWlnaHRgIG9wZXJhdGUgaW4gdGhlIGNvZGUgY2h1bmsgb3B0aW9ucy4gCgojIyBSQSBDb2RlCgpXZSB3aWxsIGVtcGxveSB0aGUgZm9sbG93aW5nIGxheW91dCBmb3IgdGhlIGRhc2hib2FyZC4KClJNYXJrZG93biBEYXNoYm9hcmQgU3RydWN0dXJlCgorIEljb24gKDQ4IHggNDgpCisgVGhlIERhdGEKKyBDb2x1bW4gMTogSW50ZXJhY3RpdmUgVGFibGUKKyBDb2x1bW4gMjogUGhvdG8KKyBVUyBTdGF0aXN0aWNzCisgQ29sdW1uIDEgCisgWWVhcmx5IERlYXRocworIFllYXJseSBDdW11bGF0aXZlIERlYXRocworIERlYXRocyBwZXIgU2hvb3RpbmcKKyBDb2x1bW4gMgorIFdvdW5kZWQKKyBEZWF0aHMKKyBTaG9vdGluZyBDb21wbGV0ZWQvQXR0ZW1wdGVkIFN1aWNpZGUKKyBNZWRpYW4gU2hvdHMgRmlyZWQKKyBEZWF0aHMsIFNob290ZXIgd2FzIE9ubHkgVmljdGltCisgVXNlIG9mIGEgU2luZ2xlIEhhbmRndW4KKyBTdGF0ZSBTdGF0aXN0aWNzCisgU2lkZWJhcgorIENvbHVtbiAxCisgWWVhcmx5IERlYXRocworIFllYXJseSBDdW11bGF0aXZlIERlYXRocworIERlYXRocyBwZXIgU2hvb3RpbmcKKyBNYXAKKyBab29tICgrKQorIFpvb20gKC0pCisgTGF5ZXIgQ29udHJvbHMKKyBQcm92aWRlciBUaWxlcworIENpcmNsZSBNYXJrZXJzCisgTWluaS1tYXAKKyBBYm91dAorIENvbHVtbiAxCisgRGlzY2xhaW1lcgorIEhvdyBkbyBJIHVzZSB0aGlzIGRhc2hib2FyZD8KKyBEb2VzIE9wZW4gQ2FzZSBTdHVkaWVzIGhhdmUgbW9yZSByZXNvdXJjZXMgSSBjYW4gYWNjZXNzIHRvIGxlYXJuIGFib3V0IGNyZWF0aW5nIHRoaXMgZGFzaGJvYXJkPworIENvbHVtbiAyOiBQaG90bworIFR1dG9yaWFsCisgU3RlcCAxOiBMb2FkIHRoZSBgZmxleGRhc2hib2FyZGAgcGFja2FnZQorIFN0ZXAgMjogQ3JlYXRlIGFuZCBgUk1EYCBkb2N1bWVudAorIFN0ZXAgMzogQ3JlYXRlIGFuIGFwcHJvcHJpYXRlIGBZQU1MYC4KKyBTdGVwIDQ6IERlc2lnbiB0aGUgbGF5b3V0IG9mIHRoZSBkYXNoYm9hcmQuCisgU3RlcCA1OiBBZGQgY29udGVudCB0byB0aGUgZGFzaGJvYXJkLgorIEhvdGxpbmUKKyBXYXJuaW5nIFNpZ25zCisgUmVzcG9uc2UgdG8gV2FybmluZyBTaWducworIFNvdXJjZSBDb2RlCgoKCgoKYGBge3IsIGV2YWw9RkFMU0V9CnNob290aW5nX2RhdGFfZ2VvY29kZWQgPC0gcmVhZF9jc3YoaGVyZSgicHJvY2Vzc2VkX2RhdGEiLAogICAgICAgICAgICAgICJzaG9vdGluZ19kYXRhLmNzdiIpKQoKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogIGZpbHRlcighaXMubmEobG9uZ2l0dWRlKSwKICAgICAgICAgIWlzLm5hKGxhdGl0dWRlKSkgJT4lCiAgc3RfYXNfc2YoY29vcmRzID0gYygibG9uZ2l0dWRlIiwgImxhdGl0dWRlIiksIGNycyA9IDQzMjYpICU+JQogIHN0X3RyYW5zZm9ybShjcnMgPSAxMDIwMDgpICU+JQogIHN0X2ppdHRlcihhbW91bnQgPSA1MCkgJT4lCiAgc3RfdHJhbnNmb3JtKGNycyA9IDQzMjYpICU+JQogIG11dGF0ZShsb25naXR1ZGUgPSBzdF9jb29yZGluYXRlcyguKVssMV0sCiAgICAgICAgIGxhdGl0dWRlID0gc3RfY29vcmRpbmF0ZXMoLilbLDJdKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1nZW9tZXRyeSkKCkRUX3RhYmxlIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgZHBseXI6OnNlbGVjdChEYXRlLAogICAgICAgICAgICAgICAgU2Nob29sLAogICAgICAgICAgICAgICAgQ2l0eSwKICAgICAgICAgICAgICAgIFN0YXRlLAogICAgICAgICAgICAgICAgYE5hcnJhdGl2ZSAoRGV0YWlsZWQgU3VtbWFyeS8gQmFja2dyb3VuZClgKSAlPiUKICByZW5hbWUoIk5hcnJhdGl2ZSIgPSBgTmFycmF0aXZlIChEZXRhaWxlZCBTdW1tYXJ5LyBCYWNrZ3JvdW5kKWApCmBgYCAgICAKCldlIGNyZWF0ZSB0aGUgKipUaGUgRGF0YSoqIHBhZ2UuIAoKYGBgCkNvbHVtbiB7ZGF0YS13aWR0aD03MDB9Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KClRoZSBkYXRhIGlzIGZyb20gdGhlIEstMTIgc2Nob29sIHNob290aW5nIGRhdGFiYXNlLiBUaGlzIGRhdGFiYXNlIHdhcyBjb21waWxlZCB1c2luZyBzZXZlcmFsIHN0ZXBzIHRvIGlkZW50aWZ5IGFuZCBhdXRoZW50aWNhdGUgaW5jaWRlbnRzLiBNZXRob2RzIGFyZSBvdXRsaW5lZCBbaGVyZV0oaHR0cHM6Ly93d3cuY2hkcy51cy9zc2RiL21ldGhvZHMvKS4KClRoZSBkYXRhYmFzZSBpbmNsdWRlcyBhIGNvZGVib29rIHRoYXQgZGVmaW5lcyBlYWNoIHZhcmlhYmxlLgoKIyMjCmBgYAoKV2UgdGhlbiBpbnNlcnQgYW4gaW50ZXJhY3RpdmUgdGFibGUuIFNpbmNlIHdlIGhhdmUgYHNoaW55YCBlbmFibGVkLCB3ZSBuZWVkIHRvIHVzZSBgREY6OnJlbmRlckRhdGFUYWJsZWAgdG8gcHJvZHVjZSB0aGUgb3V0cHV0IHdlIGRlc2lyZS4gCgpgYGB7ciwgZXZhbD1GQUxTRX0KRFQ6OnJlbmRlckRhdGFUYWJsZSh7CiAgRFQ6OmRhdGF0YWJsZShEVF90YWJsZSwKICAgICAgICAgICAgICAgIGNhcHRpb24gPSBodG1sdG9vbHM6OnRhZ3MkY2FwdGlvbigKICAgICAgICAgICAgICAgICAgc3R5bGUgPSAnY2FwdGlvbi1zaWRlOiB0b3A7IHRleHQtYWxpZ246IExlZnQ7JywKICAgICAgICAgICAgICAgICAgaHRtbHRvb2xzOjp3aXRoVGFncygKICAgICAgICAgICAgICAgICAgICBkaXYoSFRNTCgnPGEgaHJlZj0iaHR0cHM6Ly93d3cuY2hkcy51cy9zc2RiL2RhdGFzZXQvKSI+Q2xpY2sgaGVyZSB0byBiZSByZWRpcmVjdGVkIHRvIGEgcGFnZSB3aGVyZSB0aGlzIGRhdGEgY2FuIGJlIGRvd25sb2FkZWQuPC9hPicpKSkpLAogICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoYXV0b1dpZHRoID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFkgPSAnNDUwcHgnKSkKfSkKYGBgCgpJbiBhIHNlcGFyYXRlIGNvbHVtbiwgd2Ugd2lsbCBhZGQgYSByZWxldmFudCBwaG90byB0byBhcHByb3ZlIHRoZSB2aXN1YWwgYXBwZWFsIG9mIHRoZSBkYXNoYm9hcmQuIE5vdGUgdGhhdCB0aGUgd2lkdGggb2YgdGhpcyBjb2x1bW4gaXMgc2V0IHRvIDMwMC4gU2l6ZSBzcGVjaWZpY2F0aW9ucyBvbiBgZmxleGRhc2hib2FyZGAgYXJlIHVuaXRsZXNzOyB0aGUgd2lkdGggb2YgYW55IGNvbHVtbiBpbmNsdWRlZCBvbiBhIHBhZ2UgaXMgYSBmdW5jdGlvbiBvZiB0aGUgd2lkdGggc2V0IGZvciBhIGNvbHVtbiBhZ2FpbnN0IHRoZSBzdW0gb2Ygd2lkdGhzIGZvciBhbGwgY29sdW1ucyBvbiB0aGF0IHBhZ2UuIElmIHdlIHNldCBjb2x1bW5zIHNpemVzIG9mIDYwMCBhbmQgMzAwIG9uIGEgcGFnZSB3aXRoIHR3byBjb2x1bW5zLCBvbmUgY29sdW1uIHdpbGwgYmUgdHdpY2UgYXMgbGFyZ2UgYXMgdGhlIG90aGVyIGNvbHVtbi4gCgpXZSBpbmNsdWRlIGEgZmlndXJlIGNhcHRpb24gdG8gY3JlZGl0IHRoZSBhdXRob3Igb2YgdGhlIHBob3RvZ3JhcGguCgpOb3RlIHRoYXQgdGhlcmUgaXMgbm8gdGV4dCBuZXh0IHRvIHRoZSBhcmVhIHdoZXJlIHdlIHdvdWxkIG5vcm1hbGx5IHNwZWNpZnkgYSBoZWFkZXIuIEluIHRoaXMgY2FzZSwgbm8gaGVhZGVyIGlzIG5lY2Vzc2FyeSBmb3IgdGhpcyBjb250ZW50LiBgZmxleGRhc2hib2FyZGAgJiBgUk1hcmtkb3duYCByZWNvZ25pemUgdGhpcyBhbmQgcmVtb3ZlcyB0aGUgaGVhZGVyIG9wdGlvbi4gCgpgYGAKQ29sdW1uIHtkYXRhLXdpZHRoPTMwMH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjCgonJyd7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD0iW1Bob3RvZ3JhcGggYnkgUnViw6luIFJvZHJpZ3Vlel0oaHR0cHM6Ly91bnNwbGFzaC5jb20vcGhvdG9zL0lYVHZuT09TVHlVKSIsIG91dC53aWR0aCA9ICcxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInJ1YmVuLXJvZHJpZ3Vlei1JWFR2bk9PU1R5VS11bnNwbGFzaC5qcGciKQonJycKYGBgCgpMZXQncyBjcmVhdGUgYSBwYWdlIGZvciAqKlVTIFN0YXRpc3RpY3MqKiB3ZSB3b3VsZCBsaWtlIHRvIHNoYXJlLiAKCmBgYApVUyBTdGF0aXN0aWNzIHtkYXRhLWljb249ImZhLWZsYWcifQo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IApgYGAKCkxldCdzIGNyZWF0ZSBhIGNvbHVtbi4gTm90ZSB0aGUgYC50YWJzZXRgIGFuZCBgLnRhYnNldC1mYWRlYCBvcHRpb25zIHNwZWNpZmllZCBmb3IgdGhlIGNvbHVtbi4gCgpgYGAKQ29sdW1uIHtkYXRhLXdpZHRoPTcwMCAudGFic2V0IC50YWJzZXQtZmFkZX0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpgYGAKCkFmdGVyIGhhdmluZyBzcGVjaWZpZWQgdGhlIGAudGFic2V0YCBhbmQgYC50YWJzZXQtZmFkZWAgb3B0aW9ucywgd2UgY2FuIGNyZWF0ZSBlYWNoIHRhYiBpbiB0aGUgc2FtZSB3YXkgd2Ugd291bGQgY3JlYXRlIGNvbHVtbnMuIAoKYGBgCiMjIyBZZWFybHkgRGVhdGhzCgonJyd7cn0Kc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF91cyA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogICAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSIpKSAlPiUKICAgIG11dGF0ZShEYXRlX3llYXIgPSB5ZWFyKERhdGUpKSAlPiUKICAgIGdyb3VwX2J5KERhdGVfeWVhcikgJT4lCiAgICBjb3VudCgpICU+JQogICAgdW5ncm91cCgpCnN0YXJ0IDwtIDE5NzAKZW5kIDwtIDIwMjAKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF91cyAlPiUKICAgIGdncGxvdChhZXMoeCA9IERhdGVfeWVhciwgeSA9IG4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJibGFjayIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKHN0YXJ0LTEsIGVuZCsxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAiWWVhcmx5IERlYXRocyBBdHRyaWJ1dGFibGUgdG8gU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHN1YnRpdGxlID0gIlVuaXRlZCBTdGF0ZXMiLAogICAgICAgICB4ID0gIlNjaG9vbCBTaG9vdGluZ3MiLAogICAgICAgICB5ID0gIiIpCicnJwoKIyMjIFllYXJseSBDdW11bGF0aXZlIERlYXRocwoKJycne3J9CnN0YXJ0IDwtIDE5NzAKZW5kIDwtIDIwMjAKc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF91czIgPC0gc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCAlPiUKICAgIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSkgJT4lCiAgICBtdXRhdGUoRGF0ZV95ZWFyID0geWVhcihEYXRlKSkgJT4lCiAgICBncm91cF9ieShEYXRlX3llYXIpICU+JQogICAgc3VtbWFyaXplKE4gPSBuKCkpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgY29tcGxldGUoRGF0ZV95ZWFyID0gc2VxKHN0YXJ0LGVuZCxieT0xKSkgJT4lCiAgICBtdXRhdGUobl9jdW1zdW0gPSBjdW1zdW0oTikpCnNob290aW5nX2RhdGFfZ2VvY29kZWRfdXMyICU+JQogICAgZ2dwbG90KGFlcyh4ID0gRGF0ZV95ZWFyLCB5ID0gbl9jdW1zdW0pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJibGFjayIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKHN0YXJ0LTEsIGVuZCsxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAiWWVhcmx5IEN1bXVsYXRpdmUgRGVhdGhzIEF0dHJpYnV0YWJsZSB0byBTY2hvb2wgU2hvb3RpbmdzIiwKICAgICAgICAgc3VidGl0bGUgPSAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHkgPSAiIikKJycnCgojIyMgRGVhdGhzIHBlciBTaG9vdGluZwoKJycne3J9CnNob290aW5nX2RhdGFfZ2VvY29kZWRfdXMzIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikpICU+JQogICAgbXV0YXRlKERhdGVfeWVhciA9IHllYXIoRGF0ZSkpICU+JQogICAgZ3JvdXBfYnkoYEtpbGxlZCAoaW5jbHVkZXMgc2hvb3RlcilgKSAlPiUKICAgIHN1bW1hcml6ZShOID0gbigpKQpzaG9vdGluZ19kYXRhX2dlb2NvZGVkX3VzMyAlPiUKICAgIGdncGxvdChhZXMoeCA9IGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCwgeSA9IE4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJibGFjayIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAsIGJ5ID0gMSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDEwLCBieSA9IDEpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xLDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cygpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gIkRlYXRocyBwZXIgU2Nob29sIFNob290aW5nIiwKICAgICAgICAgc3VidGl0bGUgPSAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHkgPSAiIikKJycnCmBgYAoKV2UgaW5jbHVkZSBhIGNvbHVtbiBmb3IgdmFsdWUgYm94ZXMuCgpgYGAKQ29sdW1uIHtkYXRhLXdpZHRoPTMwMH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAKYGBgCgpXZSBjcmVhdGUgdGhlIGZpcnN0IHZhbHVlIGJveC4gV2Ugd2FudCB0byBkaXNwbGF5IHNvbWUgaW1wb3J0YW50IHN0YXRpc3RpY3MsIGltcG9ydGFudGx5OgoKKyBXb3VuZGVkCisgRGVhdGhzCisgU2hvb3RpbmcgQ29tcGxldGVkL0F0dGVtcHRlZCBTdWljaWRlCisgTWVkaWFuIFNob3RzIEZpcmVkCisgRGVhdGhzLCBTaG9vdGVyIHdhcyBPbmx5IFZpY3RpbQorIFVzZSBvZiBhIFNpbmdsZSBIYW5kZ3VuCgpgYGAKIyMjICoqV291bmRlZCoqCiAgICAKJycne3J9CnZhbHVlQm94KHN1bShzaG9vdGluZ19kYXRhX2dlb2NvZGVkJFdvdW5kZWQsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIGNvbG9yID0gIndoaXRlIikKJycnCmBgYAoKV2UgY3JlYXRlIHRoZSByZW1haW5pbmcgdmFsdWUgYm94ZXMKCmBgYAojIyMgKipEZWF0aHMqKgoKJycne3J9CnZhbHVlQm94KHN1bShzaG9vdGluZ19kYXRhX2dlb2NvZGVkJGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgY29sb3IgPSAid2hpdGUiKQonJycKCiMjIyAqKlNob290ZXIgQ29tcGxldGVkL0F0dGVtcHRlZCBTdWljaWRlKioKCicnJ3tyfQojIHRoaXMgbmVlZHMgdG8gYmUgd3JhbmdsZWQgaW4gdGhlIHJlZ3VsYXIgZGF0YQpzdWljaWRlIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgbXV0YXRlKGBTdWljaWRlIChvciBhdHRlbXB0ZWQgc3VpY2lkZSkgYnkgU2hvb3RlciAoWS9OKWAgPSBjYXNlX3doZW4oYFN1aWNpZGUgKG9yIGF0dGVtcHRlZCBzdWljaWRlKSBieSBTaG9vdGVyIChZL04pYCA9PSAiWWVzIiB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSkgJT4lCiAgcHVsbChgU3VpY2lkZSAob3IgYXR0ZW1wdGVkIHN1aWNpZGUpIGJ5IFNob290ZXIgKFkvTilgKQoKc3VpY2lkZSA8LSBzdW0oc3VpY2lkZSwKICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSAvIGxlbmd0aChzdWljaWRlKQoKIyB2YWx1ZUJveCgKIyAgIHBhc3RlKAojICAgICByb3VuZCgKIyAgICAgICBtZWFuKHN1aWNpZGUsCiMgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICogMTAwLAojICAgICAgIDIpLAojICAgICAiJSIpLAojICAgY29sb3IgPSAid2hpdGUiKQoKdmFsdWVCb3goCiAgcGFzdGUoCiAgICByb3VuZChzdWljaWRlICogMTAwLAogICAgICAgICAgMiksCiAgIiUiKSwKICBjb2xvciA9ICJ3aGl0ZSIpCicnJwoKIyMjICoqTWVkaWFuIFNob3RzIEZpcmVkKioKCicnJ3tyfQp2YWx1ZUJveCgKICByb3VuZCgKICBtZWRpYW4oc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgTnVtYmVyIG9mIFNob3RzIEZpcmVkYCwKICAgICAgbmEucm0gPSBUUlVFKSwKICAyKSwKICBjb2xvciA9ICJ3aGl0ZSIpCicnJwoKIyMjICoqRGVhdGhzLCBTaG9vdGVyIHdhcyBPbmx5IFZpY3RpbSoqCgonJyd7cn0KdmFsdWVCb3goCiAgcGFzdGUoCiAgICBhcy5jaGFyYWN0ZXIoCiAgICByb3VuZCgKICAgICAgMTAwICogKHN1bSgKICAgIGlmZWxzZShzaG9vdGluZ19kYXRhX2dlb2NvZGVkJGBTdWljaWRlIChTaG9vdGVyIHdhcyBvbmx5IHZpY3RpbSkgWS9OLyBOL0FgID09ICJZIiwKICAgICAgICAgICAgICAgIFRSVUUsCiAgICAgICAgICAgICAgICBGQUxTRSksIG5hLnJtID0gVFJVRSkKICAgIC8KICAgICAgc3VtKHNob290aW5nX2RhdGFfZ2VvY29kZWQkYEtpbGxlZCAoaW5jbHVkZXMgc2hvb3RlcilgLCBuYS5ybSA9IFRSVUUpKSwKICAgIDIpKSwgIiUiKSwKICBjb2xvciA9ICJ3aGl0ZSIpCicnJwoKIyMjICoqVXNlIG9mIGEgU2luZ2xlIEhhbmRndW4qKgoKJycne3J9CnZhbHVlQm94KAogIHBhc3RlKAogICAgYXMuY2hhcmFjdGVyKAogICAgcm91bmQoCiAgICAgIDEwMCAqIChzdW0oCiAgICBpZmVsc2Uoc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgRmlyZWFybSBUeXBlYCA9PSAiUmlmbGUiLAogICAgICAgICAgICAgICAgVFJVRSwKICAgICAgICAgICAgICAgIEZBTFNFKSwgbmEucm0gPSBUUlVFKQogICAgLwogICAgICBsZW5ndGgoc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgRmlyZWFybSBUeXBlYCkpLAogICAgMikpLCAiJSIpLAogIGNvbG9yID0gIndoaXRlIikKJycnCmBgYAoKV2UgdGhlbiBjcmVhdGUgdGhlIG5leHQgcGFnZSwgKipTdGF0ZSBTdGF0aXN0aWNzKiogCgpgYGAKU3RhdGUgU3RhdGlzdGljcyB7ZGF0YS1pY29uPWZhLWZsYWctY2hlY2tlcmVkfQo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IAoKQ29sdW1uIHsuc2lkZWJhciBkYXRhLXdpZHRoPTI1MH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCicnJ3tyfQpzZWxlY3RJbnB1dCgic3RhdGVfc2VsZWN0ZWQiLCBsYWJlbCA9ICJTZWxlY3QgYSBzdGF0ZSB0byBleHBsb3JlOiIsCiAgICAgICAgICAgIGNob2ljZXMgPSB1bmlxdWUobWFwX2RhdGEoInN0YXRlIikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocmVnaW9uIT0iZGlzdHJpY3Qgb2YgY29sdW1iaWEiKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwocmVnaW9uKSkgJT4lCiAgICAgICAgICAgICAgc3RyX3RvX3RpdGxlKCksIHNlbGVjdGVkID0gIk1hcnlsYW5kIikKJycnCgpDb2x1bW4ge2RhdGEtd2lkdGg9NzUwIC50YWJzZXQgLnRhYnNldC1mYWRlfQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIFllYXJseSBEZWF0aHMKCicnJ3tyfQpyZW5kZXJQbG90KHsKICBzdGFydCA8LSAxOTcwCiAgZW5kIDwtIDIwMjAKICBzdGF0ZV9kZiA8LSBhc190aWJibGUoY2JpbmQoc3RhdGUuYWJiLCBzdGF0ZS5uYW1lKSkKICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQgJT4lCiAgICByZW5hbWUoIlN0YXRlX2FiYiIgPSBTdGF0ZSkgJT4lCiAgICBsZWZ0X2pvaW4oc3RhdGVfZGYsIGJ5ID0gYygiU3RhdGVfYWJiIiA9ICJzdGF0ZS5hYmIiKSkgJT4lCiAgICByZW5hbWUoIlN0YXRlIiA9IHN0YXRlLm5hbWUpICU+JQogICAgbXV0YXRlKFN0YXRlID0gc3RyX3RvX3RpdGxlKHRvbG93ZXIoU3RhdGUpKSkgJT4lCiAgICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikpICMgdGhpcyBtdXN0IGJlIGFwcGxpZWQgdG8gd3JhbmdsaW5nCiAgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF9mIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWRbc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRTdGF0ZSA9PSBpbnB1dCRzdGF0ZV9zZWxlY3RlZCwgXQogIHNob290aW5nX2RhdGFfZ2VvY29kZWRfZiA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkX2YgJT4lCiAgICBtdXRhdGUoRGF0ZV95ZWFyID0geWVhcihEYXRlKSkgJT4lCiAgICBncm91cF9ieShEYXRlX3llYXIpICU+JQogICAgY291bnQoKSAlPiUKICAgIHVuZ3JvdXAoKQogIHNob290aW5nX2RhdGFfZ2VvY29kZWRfZiAlPiUKICAgIGdncGxvdChhZXMoeCA9IERhdGVfeWVhciwgeSA9IG4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJibGFjayIpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoc3RhcnQsIGVuZCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKHN0YXJ0LTEsIGVuZCsxKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSAiU3RhdGV3aWRlIFNjaG9vbCBTaG9vdGluZ3MiLAogICAgICAgICBzdWJ0aXRsZSA9IGlucHV0JHN0YXRlX3NlbGVjdGVkLAogICAgICAgICB4ID0gIlllYXJseSBEZWF0aHMgQXR0cmlidXRhYmxlIHRvIFNjaG9vbCBTaG9vdGluZ3MiLAogICAgICAgICB5ID0gIiIpCn0pCicnJwoKIyMjIFllYXJseSBDdW11bGF0aXZlIERlYXRocwoKJycne3J9CnJlbmRlclBsb3QoewogIHN0YXJ0IDwtIDE5NzAKICBlbmQgPC0gMjAyMAogIHN0YXRlX2RmMiA8LSBhc190aWJibGUoY2JpbmQoc3RhdGUuYWJiLCBzdGF0ZS5uYW1lKSkKICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkMiA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogICAgcmVuYW1lKCJTdGF0ZV9hYmIiID0gU3RhdGUpICU+JQogICAgbGVmdF9qb2luKHN0YXRlX2RmMiwgYnkgPSBjKCJTdGF0ZV9hYmIiID0gInN0YXRlLmFiYiIpKSAlPiUKICAgIHJlbmFtZSgiU3RhdGUiID0gc3RhdGUubmFtZSkgJT4lCiAgICBtdXRhdGUoU3RhdGUgPSBzdHJfdG9fdGl0bGUodG9sb3dlcihTdGF0ZSkpKSAlPiUKICAgIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSkgIyB0aGlzIG11c3QgYmUgYXBwbGllZCB0byB3cmFuZ2xpbmcKICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkX2YyIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQyW3Nob290aW5nX2RhdGFfZ2VvY29kZWQyJFN0YXRlID09IGlucHV0JHN0YXRlX3NlbGVjdGVkLCBdCiAgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF9mMiA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkX2YyICU+JQogICAgbXV0YXRlKERhdGVfeWVhciA9IHllYXIoRGF0ZSkpICU+JQogICAgZ3JvdXBfYnkoRGF0ZV95ZWFyKSAlPiUKICAgIHN1bW1hcml6ZShOID0gbigpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGNvbXBsZXRlKERhdGVfeWVhciA9IHNlcShzdGFydCwgZW5kLCBieT0xKSwKICAgICAgICAgICAgIGZpbGwgPSBsaXN0KE4gPSAwKSkgJT4lCiAgICBtdXRhdGUobl9jdW1zdW0gPSBjdW1zdW0oTikpCiAgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF9mMiAlPiUKICAgIGdncGxvdChhZXMoeCA9IERhdGVfeWVhciwgeSA9IG5fY3Vtc3VtKSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiYmxhY2siKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKHN0YXJ0LCBlbmQsIGJ5ID0gNSksCiAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKHN0YXJ0LCBlbmQsIGJ5ID0gNSksCiAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhzdGFydC0xLCBlbmQrMSkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gIlllYXJseSBDdW11bGF0aXZlIERlYXRocyBBdHRyaWJ1dGFibGUgdG8gU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHN1YnRpdGxlID0gaW5wdXQkc3RhdGVfc2VsZWN0ZWQsCiAgICAgICAgIHggPSAiU2Nob29sIFNob290aW5ncyIsCiAgICAgICAgIHkgPSAiIikKfSkKJycnCgojIyMgRGVhdGhzIHBlciBTaG9vdGluZwoKJycne3J9CnJlbmRlclBsb3QoewogIHN0YXRlX2RmMyA8LSBhc190aWJibGUoY2JpbmQoc3RhdGUuYWJiLCBzdGF0ZS5uYW1lKSkKICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkMyA8LSBzaG9vdGluZ19kYXRhX2dlb2NvZGVkICU+JQogICAgcmVuYW1lKCJTdGF0ZV9hYmIiID0gU3RhdGUpICU+JQogICAgbGVmdF9qb2luKHN0YXRlX2RmMywgYnkgPSBjKCJTdGF0ZV9hYmIiID0gInN0YXRlLmFiYiIpKSAlPiUKICAgIHJlbmFtZSgiU3RhdGUiID0gc3RhdGUubmFtZSkgJT4lCiAgICBtdXRhdGUoU3RhdGUgPSBzdHJfdG9fdGl0bGUodG9sb3dlcihTdGF0ZSkpKQogIHNob290aW5nX2RhdGFfZ2VvY29kZWQzIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQzICU+JQogICAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSIpKSAlPiUKICAgIG11dGF0ZShEYXRlX3llYXIgPSB5ZWFyKERhdGUpKSAlPiUKICAgIGdyb3VwX2J5KFN0YXRlLGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCkgJT4lCiAgICBzdW1tYXJpemUoTiA9IG4oKSkKICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkX2YzIDwtIHNob290aW5nX2RhdGFfZ2VvY29kZWQzW3Nob290aW5nX2RhdGFfZ2VvY29kZWQzJFN0YXRlID09IGlucHV0JHN0YXRlX3NlbGVjdGVkLCBdCiAgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZF9mMyAlPiUKICAgIGdncGxvdChhZXMoeCA9IGBLaWxsZWQgKGluY2x1ZGVzIHNob290ZXIpYCwgeSA9IE4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJibGFjayIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMzAsIGJ5ID0gMSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLDMwLCBieSA9IDEpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xLDMwKSkgKwogIHNjYWxlX3lfY29udGludW91cygpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gIkRlYXRocyBwZXIgU2Nob29sIFNob290aW5nIiwKICAgICAgICAgc3VidGl0bGUgPSBpbnB1dCRzdGF0ZV9zZWxlY3RlZCwKICAgICAgICAgeCA9ICJTY2hvb2wgU2hvb3RpbmdzIiwKICAgICAgICAgeSA9ICIiKQp9KQonJycKYGBgCgpXZSB0aGVuIGNyZWF0ZSB0aGUgKipNYXAqKiBwYWdlLiAKCmBgYApDb2x1bW4ge2RhdGEtd2lkdGg9MTAwMH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAKICAgIAojIyMgCiAgICAKJycne3J9CiMgd291bGQgYmUgYSBncmVhdCBpZGVhIHRvIGFkZCBhIHNsaWRlciBoZXJlIGlmIHBvc3NpYmxlCiMgZ29vZCBzaXRlIGZvciBpY29ucyBodHRwczovL2ljb25hcmNoaXZlLmNvbS8KCnNob290aW5nX2luZm9ybWF0aW9uMCA8LSBwYXN0ZSgnPGRpdiBzdHlsZT0iaGVpZ2h0OmF1dG87bGluZS1oZWlnaHQ6MWVtO292ZXJmbG93OnZpc2libGU7cGFkZGluZzo1cHg7Ij4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkJERhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8Yj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkJFNjaG9vbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwvYj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG9vdGluZ19kYXRhX2dlb2NvZGVkJGBOYXJyYXRpdmUgKERldGFpbGVkIFN1bW1hcnkvIEJhY2tncm91bmQpYCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwvZGl2PiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICI8YnIvPiIKKQoKIyBpY29uX3NldCA8LSBpY29ucygKIyAgIGljb25VcmwgPSBjYXNlX3doZW4oc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgRmlyZWFybSBUeXBlYD09IkhhbmRndW4iIH4gImh0dHBzOi8vaWNvbnMuaWNvbmFyY2hpdmUuY29tL2ljb25zL2ljb25zOC93aW5kb3dzLTgvNDgvTWlsaXRhcnktR3VuLWljb24ucG5nIiwKIyAgICAgICAgICAgICAgICAgICAgICAgc2hvb3RpbmdfZGF0YV9nZW9jb2RlZCRgRmlyZWFybSBUeXBlYD09IlJpZmxlIiB+ICJodHRwczovL2ljb25zLmljb25hcmNoaXZlLmNvbS9pY29ucy9pY29uczgvd2luZG93cy04LzQ4L01pbGl0YXJ5LVJpZmxlLWljb24ucG5nIiwKIyAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJodHRwczovL2ljb25zLmljb25hcmNoaXZlLmNvbS9pY29ucy9kcnlpY29ucy9hZXN0aGV0aWNhLTIvNDgvcGFnZS1zZWFyY2gtaWNvbi5wbmciKSwKIyAgIGljb25XaWR0aCA9IDIwLAojICAgaWNvbkhlaWdodCA9IDIwCiMgKQoKbGVhZmxldChzaG9vdGluZ19kYXRhX2dlb2NvZGVkKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gcHJvdmlkZXJzJE9wZW5TdHJlZXRNYXAsIGdyb3VwID0gIk9wZW5TdHJlZXRNYXAiKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gcHJvdmlkZXJzJEVzcmkuV29ybGRJbWFnZXJ5LCBncm91cCA9ICJFU1JJIFdvcmxkIEltYWdlcnkiKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gcHJvdmlkZXJzJFN0YW1lbi5Ub25lckxpdGUsIGdyb3VwID0gIlRvbmVyIExpdGUiKSAlPiUKICBhZGRDaXJjbGVNYXJrZXJzKHBvcHVwID0gfnNob290aW5nX2luZm9ybWF0aW9uMCwKICAgICAgICAgICAgICAgICAgIGxuZyA9IH5sb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgICBsYXQgPSB+bGF0aXR1ZGUsCiAgICByYWRpdXMgPSA1LAogICAgY29sb3IgPSAicmVkIiwKICAgIGZpbGxPcGFjaXR5ID0gMC4yLAogICAgc3Ryb2tlID0gVFJVRSwKICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSwKICAgIGdyb3VwID0gIkNpcmNsZXMiKSAlPiUKICAjIGFkZE1hcmtlcnMobG5nID0gfmxvbmdpdHVkZSwKICAjICAgICAgICAgICAgICAgICAgbGF0ID0gfmxhdGl0dWRlLAogICMgICAgICAgICAgICBwb3B1cCA9IH5zaG9vdGluZ19pbmZvcm1hdGlvbjAsCiAgIyAgICAgICAgICAgICAgICAgIGljb24gPSBpY29uX3NldCwKICAjICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiVEVTVEVSIikgJT4lCiAgYWRkTWluaU1hcCh0aWxlcyA9IHByb3ZpZGVycyRTdGFtZW4uVG9uZXIsCiAgICAgICAgICAgICB0b2dnbGVEaXNwbGF5ID0gVFJVRSwKICAgICAgICAgICAgIG1pbmltaXplZCA9IEZBTFNFKSAlPiUKICBhZGRMYXllcnNDb250cm9sKAogICAgYmFzZUdyb3VwcyA9IGMoIlRvbmVyIExpdGUiLAogICAgICAgICAgICAgICAgICAgIk9wZW5TdHJlZXRNYXAiLAogICAgICAgICAgICAgICAgICAgIkVTUkkgV29ybGQgSW1hZ2VyeSIpLAogICAgb3ZlcmxheUdyb3VwcyA9IGMoIkNpcmNsZXMiKSwKICAgICMgb3ZlcmxheUdyb3VwcyA9IGMoIkNpcmNsZXMiLCAiVEVTVEVSIiksCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gVFJVRSkKICApICU+JQogIHNldFZpZXcobG5nID0gLTk4LjM1LCBsYXQgPSAzOS41LCB6b29tID0gNCkKIyBoaWRlR3JvdXAoYygiQ2lyY2xlcyIsICJURVNURVIiKSkKIyBuZWVkIHRvIGppdHRlciBjb29yZGluYXRlcyBieSBhIGZldyBtZXRlcnMgZm9yIHJlcGVhdHMKJycnCmBgYAoKV2UgdGhlbiBjcmVhdGUgdGhlICoqQWJvdXQqKiBwYWdlLgoKYGBgCkFib3V0IHtkYXRhLWljb249ImZhLXF1ZXN0aW9uLWNpcmNsZSJ9Cj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gCgpDb2x1bW4ge2RhdGEtd2lkdGg9NzAwfQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMKCioqV2hhdCBpcyB0aGUgcHVycG9zZSBvZiB0aGlzIGRhc2hib2FyZD8qKgoKVGhpcyBkYXNoYm9hcmQgaGFzIHR3byBwdXJwb3NlczoKCisgSWxsdXN0cmF0ZSB0cmVuZHMgaW4gc2Nob29sIHNob290aW5ncworIERlbW9uc3RyYXRlIGhvdyB0byBjcmVhdGUgYSBkYXNoYm9hcmQgdXNpbmcgYFJgCgoqKkkgd2FudCB0byBsZWFybiBob3cgdG8gY3JlYXRlIGEgZGFzaGJvYXJkIGp1c3QgbGlrZSB0aGlzLioqCgpWaXNpdCB0aGUgKlR1dG9yaWFsKiBwYWdlIG9mIHRoaXMgZGFzaGJvYXJkIHRvIGZpcnN0IGxlYXJuIHRoZSBiYXNpY3MgYWJvdXQgYnVpbGRpbmcgYSBkYXNoYm9hcmQuCgpBdCB0aGUgZW5kIG9mIHRoZSB0dXRvcmlhbCB3ZSBwcm92aWRlIGEgbGluayB0byB0aGlzIFtzdXBwbGVtZW50YXJ5IHJlc291cmNlIGJ5IHRoZSBPcGVuIENhc2UgU3R1ZGllcyBwcm9qZWN0XShJTkNMVURFIExJTksgSEVSRSkuCgpXZSBoYXZlIGluY2x1ZGVkIHRoZSBzb3VyY2UgY29kZSAoc2VlIHVwcGVyIHJpZ2h0LWhhbmQgY29ybmVyKSBpbiB0aGlzIGRhc2hib2FyZCBmb3IgbW9yZSBleHBlcmllbmNlZCBgUmAgdXNlcnMgbG9va2luZyB0byBtaW1pYyBzb21lIG9mIHdoYXQgd2UgZGlkIGluIHRoaXMgZGFzaGJvYXJkIGluIHRoZWlyIG93bi4KCioqRGlzY2xhaW1lcioqCgpUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouCgpBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiAKCkNvbHVtbiB7ZGF0YS13aWR0aD0zMDB9Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIwoKJycne3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9IltQaG90b2dyYXBoIGJ5IFJ1YsOpbiBSb2RyaWd1ZXpdKGh0dHBzOi8vdW5zcGxhc2guY29tL3Bob3Rvcy9JWFR2bk9PU1R5VSkiLCBvdXQud2lkdGggPSAnMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJuYXRoYW4tZHVtbGFvLXhQSG1tVktTOGxNLXVuc3BsYXNoLmpwZyIpCicnJwpgYGAKCldlIGNyZWF0ZSBhICoqVHV0b3JpYWwqKiBwYWdlIHRoYXQgbGlua3MgdG8gdGhpcyByZXNvdXJjZS4gCgpgYGAKVHV0b3JpYWwgey5zdG9yeWJvYXJkIGRhdGEtaWNvbj0iZmEtbGlzdC1vbCJ9Cj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICAgCgojIyMgKioxKSoqIExvYWQgdGhlIGBmbGV4ZGFzaGJvYXJkYCBwYWNrYWdlLgoKSW5zdGFsbCB0aGUgcGFja2FnZSBpZiB5b3UgZG9uJ3QgaGF2ZSB0aGUgcGFja2FnZSBpbnN0YWxsZWQgYWxyZWFkeQoKJycne3IsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiZmxleGRhc2hib2FyZCIpCmluc3RhbGwucGFja2FnZXMoInNoaW55IikKJycnCgpPbmNlIGluc3RhbGxlZCwgdGhlIHBhY2thZ2UgaXMgcmVhZHkgdG8gYmUgbG9hZGVkIGludG8gdGhlIGBSYCBlbnZpcm9ubWVudC4KCicnJ3tyLCBlY2hvPVRSVUV9CmxpYnJhcnkoZmxleGRhc2hib2FyZCkKbGlicmFyeShzaGlueSkKJycnCgpUaGlzIGFsbCBuZWVkcyB0byBiZSBkb25lIHNlcGFyYXRlbHkgaW4gdGhlIGBSYCBjb25zb2xlLgoKIyMjICoqMikqKiBDcmVhdGUgYW4gYFJNRGAgZG9jdW1lbnQuICAgCgpEYXNoYm9hcmRzIGNhbiBiZSBjcmVhdGVkIHdpdGggYGZsZXhkYXNoYm9hcmRgIGluIHRoZSBgSFRNTGAgZm9ybWF0LiAKCmBmbGV4ZGFzaGJvYXJkYCB1c2VzIGBSTWFya2Rvd25gIHRvIHByb2R1Y2UgZGFzaGJvYXJkcyB0aGF0IGNhbiBjb250YWluIGBSYCBvdXRwdXQuCgpUaGlzIG1ha2VzIGl0IHBvc3NpYmxlIHRvIGluY2x1ZGUgc2V2ZXJhbCBtZWRpdW1zIGluIG91ciBkYXNoYm9hcmQgc3VjaCBhcyBwbG90cyBjcmVhdGVkIHdpdGggYGdncGxvdGAgb3IgbWFwcyBjcmVhdGVkIHdpdGggYGxlYWZsZXRgLgogICAgCiMjIyAqKjMpKiogQ3JlYXRlIGFuIGFwcHJvcHJpYXRlIGBZQU1MYC4KClRoZSB1c2Ugb2YgYGZsZXhkYXNoYm9hcmRgIGFsdGVycyB0aGUgd2F5IGBSTWFya2Rvd25gIGRvY3VtZW50cyBmdW5jdGlvbi4gVGhlc2UgYWx0ZXJlZCBmdW5jdGlvbnMgYXJlIGxhcmdlbHkgZGVwZW5kZW50IG9uIHRoZSBtZXRhZGF0YSB3ZSB1c2UgdG8gcHJvZHVjZSB0aGUgZGFzaGJvYXJkLiBNZXRhZGF0YSBmb3IgdGhlIGRhc2hib2FyZCBjYW4gYmUgY29uZmlndXJlZCBpbiB0aGUgYFlBTUxgIG9mIHRoZSBgUk1EYC4gCgpBbiBgSFRNTGAgZG9jdW1lbnQgY3JlYXRlZCB3aXRoIGBSTWFya2Rvd25gIGluY2x1ZGVzIGEgYFlBTUxgIHRoYXQgaXMgc29tZSB2YXJpYXRpb24gb2YgdGhpczoKCicnJwotLS0KdGl0bGU6ICJVbnRpdGxlZCIKYXV0aG9yOiAiTWljaGFlbCBPbnRpdmVyb3MiCmRhdGU6ICI4LzEyLzIwMjAiCm91dHB1dDogaHRtbF9kb2N1bWVudAotLS0KJycnCgpXZSB1c2VkIHRoZSBmb2xsb3dpbmcgYFlBTUxgIGZvciB0aGlzIGRhc2hib2FyZDoKCicnJwpvdXRwdXQ6IAogIGZsZXhkYXNoYm9hcmQ6OmZsZXhfZGFzaGJvYXJkOgogICAgbG9nbzogaHR0cHM6Ly9pY29ucy5pY29uYXJjaGl2ZS5jb20vaWNvbnMvaWNvbnM4L3dpbmRvd3MtOC80OC9Qcm9ncmFtbWluZy1EYXNoYm9hcmQtaWNvbi5wbmcKICAgIHRoZW1lOiByZWFkYWJsZQogICAgb3JpZW50YXRpb246IGNvbHVtbnMKICAgIHNvdXJjZTogZW1iZWQKICAgIHZlcnRpY2FsX2xheW91dDogZmlsbApydW50aW1lOiBzaGlueQonJycKCldlIGludHJvZHVjZSBhbiBpY29uLCBwcm92aWRlIGEgdGhlbWUgd2l0aCBhIGNvbG9yIHNjaGVtZSwgZGVmaW5lIHRoZSBvcmllbnRhdGlvbiAoYW5kIHRodXMgb3JkZXIpIG9mIGNvZGVkIG91dHB1dCwgaW5jbHVkZSB0aGUgY29kZSB1c2VkLCBsaW1pdCBzY3JvbGxpbmcsIGFuZCBhbGxvdyBgc2hpbnlgIHdpZGdldHMgdG8gYmUgdXNlZC4KCiMjIyAqKjQpKiogRGVzaWduIHRoZSBsYXlvdXQgb2YgdGhlIGRhc2hib2FyZC4KCkRhc2hib2FyZHMgYXJlIGluaGVyZW50bHkgdmlzdWFsLCBtYWtpbmcgdGhpcyBzdGVwIHRoZSBtb3N0IHRpbWUgaW50ZW5zaXZlIGFmdGVyIGNvbnRlbnQgY3JlYXRpb24uIFdlIG5lZWQgdG8gcHJlc2VudCB0aGUgZGF0YSBpbiBhIHdheSB0aGF0IGlzIGJvdGggbWVhbmluZyBhbmQgdmlzdWFsbHkgYXBwZWFsaW5nLgoKT24gdGhpcyBkYXNoYm9hcmQsIHdlIHdhbnRlZCB0byBwcmVzZW50IHN0YXRpYyBwbG90cyBvZiB0aGUgVW5pdGVkIFN0YXRlcyBhbmQgb2YgaW5kaXZpZHVhbCBzdGF0ZXMuIFdlIGFsc28gd2FudGVkIHRvIGRpc3BsYXkgdGhlIGxvY2F0aW9ucyBvZiBzY2hvb2wgc2hvb3RpbmdzIGFuZCBwcm92aWRlIHNvbWUgaW5mb3JtYXRpb24gYWJvdXQgc2Nob29sIHNob290aW5ncy4gQXNpZGUgZnJvbSBiZWluZyBhIGRhc2hib2FyZCwgd2Ugd2FudGVkIHRvIGNyZWF0ZSBhbiBlZHVjYXRpb25hbCByZXNvdXJjZSB0aGF0IHdhcyByZXByb2R1Y2libGUgZm9yIG90aGVycy4gTGFzdGx5LCBhcyBhIHNlbnNpdGl2ZSB0b3BpYywgd2Ugd2FudGVkIHRvIHJhaXNlIGF3YXJlbmVzcyBhbmQgcHJvdmlkZSBpbmZvcm1hdGlvbiB0aGF0IGNvdWxkIGhlbHAgb3RoZXJzIGFjdC4KCkdpdmVuIHRoZXNlIGdvYWxzLCB3ZSBkZWNpZGVkIG9uIHRoZSBmb2xsb3dpbmcgcGFnZSBsYXlvdXQ6CgorIFRoZSBEYXRhCisgVVMgU3RhdGlzdGljcworIFN0YXRlIFN0YXRpc3RpY3MKKyBNYXAKKyBBYm91dAorIFR1dG9yaWFsCisgSG90bGluZQorIFNvdXJjZSBDb2RlCgpUaGlzIGxheW91dCBlbnN1cmVkIHRoYXQgd2UgZGlkIHRvIG5vdCBpbmNsdWRlIHRvbyBtYW55IGNvbXBvbmVudHMuCgpUaGUgZmlyc3QgcGFnZSBnaXZlcyB1c2VycyB0byB0aGUgb3Bwb3J0dW5pdHkgdG8gbG9vayBhdCB0aGUgZGF0YSB0aGVtc2VsdmVzLiBNb3JlIGNvbXBsaWNhdGVkIGNvbXBvbmVudHMgc3VjaCBhcyB0aGUgbWFwIG9mIGVhY2ggaW5jaWRlbnQgd2VyZSBsZWZ0IGFsb25lIG9uIGEgc2luZ2xlIHBhZ2UuIFVTIGFuZCBzdGF0ZS1sZXZlbCBzdGF0aXN0aWNzIHdlcmUgc2VwYXJhdGVkIGZyb20gb25lIGFub3RoZXIuIFRoaXMgc2hvcnQgdHV0b3JpYWwgb24gaG93IHRvIGNyZWF0ZSB0aGUgZGFzaGJvYXJkIGFuZCBzb3VyY2UgY29kZSB3ZXJlIGluY2x1ZGVkIGluIHRoZSBkYXNoYm9hcmQgd2l0aCBwcm9ncmFtbWVycyBhdCBhbGwgbGV2ZWxzIGluIG1pbmQuIFRoZSBnb2FscyBvZiB0aGUgZGFzaGJvYXJkIGFuZCBhY3Rpb25hYmxlIGluZm9ybWF0aW9uIHdlcmUgZWFjaCBnaXZlbiBzZXBhcmF0ZSBwYWdlcyBmcm9tIHRoZSBvdXRwdXQuIAoKRm9yIHlvdXIgZGFzaGJvYXJkLCB0aGlzIG1heSB0YWtlIGFzIGxvbmcgYXMgdGhlIG91dHB1dCB5b3Ugd291bGQgbGlrZSB0byBzaGFyZSB0b29rIHlvdSB0byBwcm9kdWNlLiAKCiMjIyAqKjUpKiogQWRkIGNvbnRlbnQgdG8gdGhlIGRhc2hib2FyZC4KCllvdSBjYW4gYmVnaW4gYWRkaW5nIGNvbnRlbnQgdG8gdGhlIGRhc2hib2FyZCBvbmNlIHlvdSBoYXZlIGFuIGluaXRpYWwgbGF5b3V0IGluIG1pbmQuIEtlZXAgaW4gbWluZCB0aGF0IHRoaXMgd2lsbCBsaWtlbHkgYmUgYW4gaXRlcmF0aXZlIHByb2Nlc3MuIAoKVGhlIGBSTWFya2Rvd25gIGZpbGUgdXNlZCB0byBjcmVhdGUgYSBkYXNoYm9hcmQgd2l0aCBgZmxleGRhc2hib2FyZGAgd29ya3Mgc2ltaWxhcmx5IHRvIGFueSBvdGhlciBgUk1hcmtkb3duYC4gVGhlcmUgYXJlIHNvbWUgZXhjZXB0aW9ucy4KCicnJ3tyLCBlY2hvID0gVFJVRX0KIyBUaGlzIG91dHB1dCB3YXMgY3JlYXRlZCB3aXRoIGNodW5rIG9wdGlvbnM6IHtyLCBlY2hvID0gVFJVRX0KcGFzdGUoIkNvZGUgY2h1bmtzIGNhbiBiZSBleHBsaWNpdGx5IGluY2x1ZGVkIikKJycnCgonJyd7cn0KIyBUaGlzIG91dHB1dCB3YXMgY3JlYXRlZCB3aXRoIGNodW5rIG9wdGlvbnM6IHtyfQpwYXN0ZSgiQ29kZSBjaHVua3MgYXJlIGhpZGRlbiBieSBkZWZhdWx0IikKJycnCgpQYWdlcyBhbmQgY29sdW1ucyB3aXRoaW4gcGFnZXMgY2FuIGJlIGRlZmluZWQuCgonJycKUGFnZQo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAgIAoKQ29sdW1uIHtkYXRhLXdpZHRoPTUwMH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKQ29sdW1uIHtkYXRhLXdpZHRoPTUwMH0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQonJycKCkFzIG1lbnRpb25lZCBiZWZvcmUsIHRoZSBgZmxleGRhc2hib2FyZGAgbWV0YWRhdGEgaW5jbHVkZWQgaW4gdGhlIGBZQU1MYCBkb2VzIGFsc28gYWx0ZXIgaG93IGBSTWFya2Rvd25gIGZ1bmN0aW9ucy4gRm9yIG1vcmUgb24gaG93IHlvdSBjYW4gbGV2ZXJhZ2UgYm90aCBgUk1hcmtkb3duYCBhbmQgYGZsZXhkYXNoYm9hcmRgIHRvIHByb2R1Y2UgYSBkYXNoYm9hcmQsIGNsaWNrIFtoZXJlXShodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9mbGV4ZGFzaGJvYXJkL2luZGV4Lmh0bWwpLgoKVGhpcyBbc3VwcGxlbWVudGFyeSByZXNvdXJjZSBieSB0aGUgT3BlbiBDYXNlIFN0dWRpZXMgcHJvamVjdF0oSU5DTFVERSBMSU5LIEhFUkUpIHByb3ZpZGVzIGEgY2FzZSBzdHVkeSBvbiBob3cgdG8gY3JlYXRlIHRoaXMgdmVyeSBkYXNoYm9hcmQgaW4gbW9yZSBkZXRhaWwuCmBgYAoKTGFzdGx5LCB3ZSBjcmVhdGUgYSAqKkhvdGxpbmUqKiBwYWdlIHRvIHNwcmVhZCBhd2FyZW5lc3MuCgpgYGAKSG90bGluZSB7ZGF0YS1pY29uPSJmYS1leGNsYW1hdGlvbi10cmlhbmdsZSJ9Cj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICAgCgpDb2x1bW4ge2RhdGEtd2lkdGg9NjAwfQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMKCioqV2FybmluZyBTaWducyoqCgpGcm9tIFtTYW5keSBIb29rIFByb21pc2VdKGh0dHBzOi8vd3d3LnNhbmR5aG9va3Byb21pc2Uub3JnL2d1bi12aW9sZW5jZS9rbm93LXRoZS1zaWducy1vZi1ndW4tdmlvbGVuY2UvKS4uLgoKYXZvY2Fkby4uLiB0aGVyZSB3ZXJlIHNvbWUgcmVhbGx5IGludGVyZXN0aW5nIHRoaW5ncyBoZXJlLi4uIGJ1dCBkb250IGtub3cgd2hlcmUvaWYgdG8gaW5jbHVkZQpodHRwczovL3d3dy5zYW5keWhvb2twcm9taXNlLm9yZy9ndW4tdmlvbGVuY2UvMTYtZmFjdHMtYWJvdXQtZ3VuLXZpb2xlbmNlLWFuZC1zY2hvb2wtc2hvb3RpbmdzLwoKVGhlIG1vc3QgaW1wb3J0YW50IHNlZW1zIHRvIGJlIHRoYXQgc2hvb3RlcnMgdXN1YWxseSB3YXJuIHNvbWVvbmUKCjxzdHlsZT4KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9Cjwvc3R5bGU+CjxkaXYgY2xhc3MgPSAiYmx1ZSI+CgpIZXJlIGlzIGEgbGlzdCBvZiBwb3RlbnRpYWwgd2FybmluZyBzaWducyB0aGF0IGNhbiBzaWduYWwgYW4gaW5kaXZpZHVhbCBtYXkgYmUgaW4gY3Jpc2lzIGFuZC9vciBuZWVkIGhlbHA6CgorIFN1ZGRlbmx5IHdpdGhkcmF3aW5nIGZyb20gcGVvcGxlIGFuZCBhY3Rpdml0aWVzCisgQ29uc2lzdGVudCBidWxseWluZyBvciBpbnRpbWlkYXRpbmcgb3RoZXJzLCBvciBiZWluZyBidWxsaWVkIGJ5IG90aGVycworIEV4dHJlbWUgbW9vZCBvciBwZXJzb25hbGl0eSBjaGFuZ2VzCisgVmljdGltIG9mIGNvbnN0YW50IHNvY2lhbCByZWplY3Rpb24KKyBUYWxraW5nIGFib3V0IHBsYW5zIG9yIGFjdGl2ZWx5IG1ha2luZyBwbGFucyB0byBoYXJtIHRoZW1zZWx2ZXMgb3Igb3RoZXJzCisgQnJpbmdpbmcgYSB3ZWFwb24gdG8gc2Nob29sIOKAkyBvciB0aHJlYXRlbmluZyBvciB0YWxraW5nIGFib3V0IGRvaW5nIHNvCisgQnJhZ2dpbmcgYWJvdXQgb3Igd2FybmluZyBvdGhlcnMgYWJvdXQgYW4gdXBjb21pbmcgYWN0IG9mIHZpb2xlbmNlCisgUmVjcnVpdGluZyBvdGhlcnMgdG8gam9pbiBpbiBhIHBsYW5uZWQgYWN0IG9mIHZpb2xlbmNlCisgV2FybmluZyBzdHVkZW50cyB0byBzdGF5IGF3YXkgZnJvbSBzY2hvb2wgb3IgZXZlbnRzCisgRXhwcmVzc2luZyBmYXNjaW5hdGlvbiB3aXRoIGd1bnMgYW5kL29yIHNjaG9vbCBzaG9vdGluZ3MKKyBFeHByZXNzaW5nIGhvcGVsZXNzbmVzcyBhYm91dCB0aGUgZnV0dXJlCisgRXh0cmVtZSwgcHJvbG9uZ2VkIHNhZG5lc3Mgb3IgZGlzdHJlc3MKKyBFeHByZXNzaW5nIG9yIHNob3dpbmcgZmVlbGluZ3Mgb2YgaXNvbGF0aW9uCisgQnJhZ2dpbmcgYWJvdXQgYWNjZXNzIHRvIGd1bnMKCioqTk9URSoqCgpUaGlzIGxpc3QgaXMgbm90IGEgY29tcHJlaGVuc2l2ZSBsaXN0IG9mIHdhcm5pbmcgc2lnbnMgbm9yIGRvZXMgZXhoaWJpdGluZyBvbmUgb2YgdGhlc2Ugc2lnbnMgaW5kaWNhdGUgaW1taW5lbnQgdmlvbGVuY2UuCgpXaGVuIGNvbmNlcm5lZCBhYm91dCBzZWVpbmcgdHJvdWJsaW5nIGJlaGF2aW9ycywgdGVsbCBhIHRydXN0ZWQgYWR1bHQgb3IgY2FsbCA5MTEsIGlmIHRoZXJlIGlzIGFuIGltbWVkaWF0ZSB0aHJlYXQuCgo8L2Rpdj4KCkNvbHVtbiB7ZGF0YS13aWR0aD00MDB9Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAKCioqUmVzcG9uZCB0byBXYXJuaW5nIFNpZ25zKioKCkNhbGwgOTExIGlmIHlvdSBmZWVsIHRoZXJlIGlzIGFuIGltbWVkaWF0ZSB0aHJlYXQuIAoKQ2FsbCBbKzEtODQ0LTUtU0FZTk9XXSh0ZWw6MTg0NDU3Mjk2NjkpIGlmIHlvdSB3b3VsZCB0byBzdWJtaXQgYW4gYW5vbnltb3VzIHNhZmV0eSBjb25jZXJuLgpgYGAKCiMjICoqU3VtbWFyeSoqCioqKiAKCiMjIyBTdW1tYXJ5IFBsb3QKCiMjIyBTeW5vcHNpcwoKIyMgKipTdWdnZXN0ZWQgSG9tZXdvcmsqKgoqKiogCgpDcmVhdGUgYW5vdGhlciBkYXNoYm9hcmQgd2l0aCBncmFwaHMgYW5kIHN0YXRpc3RpY3MgZmVhdHVyaW5nIG90aGVyIGVsZW1lbnRzIHdpdGhpbiB0aGlzIGRhdGFzZXQuIEZvciBleGFtcGxlLCBzdHVkZW50cyBtYXkgY3JlYXRlIGdyYXBocyB0aGF0IGV4cGxvcmUgd2hhdCBzY2hvb2wgZXZlbnRzIGFyZSByZXBvcnRlZCB0byBoYXZlIG1vcmUgc2hvb3RpbmdzLgoKCiMjICoqQWRkaXRpb25hbCBJbmZvcm1hdGlvbioqCioqKgoKIyMjIEhlbHBmdWwgTGlua3MKCltSU3R1ZGlvXShodHRwczovL3JzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vZmVhdHVyZXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0NoZWF0c2hlZXQgb24gUlN0dWlkbyBJREVdKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL3Jhdy9tYXN0ZXIvcnN0dWRpby1pZGUucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW090aGVyIFJTdHVkaW8gY2hlYXRzaGVldHNdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSAgIApbVGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgIAoKW1Jlc3BvbnNlIGJpYXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Jlc3BvbnNlX2JpYXMpICAKW0Nyb3NzLVNlY3Rpb25hbCBkYXRhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy1zZWN0aW9uYWxfZGF0YT9vbGRmb3JtYXQ9dHJ1ZSkKW1BvcHVsYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BvcHVsYXRpb24/b2xkZm9ybWF0PXRydWUpCltTYW1wbGVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NhbXBsaW5nXyhzdGF0aXN0aWNzKT9vbGRmb3JtYXQ9dHJ1ZSkKW1NhbXBsaW5nIG1ldGhvZHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NhbXBsaW5nXyhzdGF0aXN0aWNzKT9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSAKW0luZmVyZW5jZV0oaHR0cHM6Ly93d3cuYnJpdGFubmljYS5jb20vc2NpZW5jZS9pbmZlcmVuY2Utc3RhdGlzdGljcykgCgpbQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAoQVNDKV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2FjcykgIAoKU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbWVyaWNhbl9Db21tdW5pdHlfU3VydmV5KSBmb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc3VydmV5ICAKW01lYXN1cmUgb2YgQW1lcmljYV0oaHR0cHM6Ly93d3cuc3NyYy5vcmcvcHJvZ3JhbXMvdmlldy9tb2EvKSAgIApbU29jaWFsIFNjaWVuY2UgUmVzZWFyY2ggQ291bmNpbF0oaHR0cHM6Ly93d3cuc3NyYy5vcmcvKSAKICAgCgpbUGlwaW5nIGluIFJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbV3JpdGluZyBmdW5jdGlvbnNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZnVuY3Rpb25zLmh0bWwpICAgCkFsc28gc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYmxvb21iZXJnLXZhcGluZy1jYXNlLXN0dWR5Lyl7dGFyZ2V0PSJfYmxhbmsifSAgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gd3JpdGluZyBmdW5jdGlvbnMuICAgCltTdHJpbmcgbWFuaXB1bGF0aW9uIGNoZWF0c2hlZXRdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltUYWJsZSBmb3JtYXRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YSl7dGFyZ2V0PSJfYmxhbmsifQoKW1JlZ3Jlc3Npb25dKGh0dHBzOi8vbGluZGVsb2V2LmdpdGh1Yi5pby90ZXN0cy1hcy1saW5lYXIvKSAgICAKW3NpbXBsZSBsaW5lYXIgcmVncmVzc2lvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2ltcGxlX2xpbmVhcl9yZWdyZXNzaW9uKSAgIApbbW9ub3RvbmljIGFzc29jaWF0aW9uXShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uY29tL21vbm90b25pYy1yZWxhdGlvbnNoaXAvKSAgIApbS2VuZGFsbCByYW5rIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9LZW5kYWxsX3JhbmtfY29ycmVsYXRpb25fY29lZmZpY2llbnQ/b2xkZm9ybWF0PXRydWUpICAgCltOdWxsIGh5cG90aGVzaXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL051bGxfaHlwb3RoZXNpcykgICAKW0FsdGVybmF0aXZlIGh5cG90aGVzaXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0FsdGVybmF0aXZlX2h5cG90aGVzaXMpICAgCltQcm9iYWJpbGl0eV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUHJvYmFiaWxpdHkpICAgCltvbmUtc2lkZWQgYW5kIHR3by1zaWRlZCBoeXBvdGhlc2VzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PbmUtX2FuZF90d28tdGFpbGVkX3Rlc3RzKSAgIApbTm9ucGFyYW1ldHJpY10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTm9ucGFyYW1ldHJpY19zdGF0aXN0aWNzKSAgICAgW1BhcmFtZXRyaWNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhcmFtZXRyaWNfc3RhdGlzdGljcykgCltzaWduaWZpY2FuY2UgdGhyZXNob2xkXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TdGF0aXN0aWNhbF9zaWduaWZpY2FuY2UpICAKW1ogc2NvcmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1N0YW5kYXJkX3Njb3JlKSAgIApbWiBzY29yZSB0YWJsZV0oaHR0cHM6Ly9zb2NyYXRpYy5vcmcvcXVlc3Rpb25zLzU5ODZhM2UxYjcyY2ZmNmZkNDhhNTQwOCkgIApbWiBzY29yZSB0byBwLXZhbHVlIGNhbGN1bGF0b3JdKGh0dHBzOi8vd3d3LnNvY3NjaXN0YXRpc3RpY3MuY29tL3B2YWx1ZXMvbm9ybWFsZGlzdHJpYnV0aW9uLmFzcHgpICAgCgoKW2BnZ3Bsb3QyYCBwYWNrYWdlXShodHRwOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIApQbGVhc2Ugc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtY28yLWVtaXNzaW9ucy8pICBmb3IgbW9yZSBkZXRhaWxzIG9uIHVzaW5nIGBnZ3Bsb3QyYCAgICAKW2dyYW1tYXIgb2YgZ3JhcGhpY3NdKGh0dHA6Ly92aXRhLmhhZC5jby5uei9wYXBlcnMvbGF5ZXJlZC1ncmFtbWFyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAKW2BnZ3Bsb3QyYCB0aGVtZXNdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZ3RoZW1lLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAKW2BkaXJlY3RsYWJlbHNgIHBhY2thZ2UgbWV0aG9kc10oaHR0cDovL2RpcmVjdGxhYmVscy5yLWZvcmdlLnItcHJvamVjdC5vcmcvZG9jcy9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIApbSG1vbmcgcGVvcGxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9IbW9uZ19wZW9wbGUpICAgCltJbnRlcnNlY3Rpb25zXShodHRwczovL3d3dy52b3guY29tL3RoZS1oaWdobGlnaHQvMjAxOS81LzIwLzE4NTQyODQzL2ludGVyc2VjdGlvbmFsaXR5LWNvbnNlcnZhdGlzbS1sYXctcmFjZS1nZW5kZXItZGlzY3JpbWluYXRpb24pICAgCgpbTW90aXZhdGluZyBhcnRpY2xlIGZvciB0aGlzIGNhc2Ugc3R1ZHkgYWJvdXQgeW91dGggZGlzY29ubmVjdGlvbi9vcHBvcnR1bml0eSB5b3V0aF0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNjI0MzQ0Ni8pCgoKVG8gbGVhcm4gbW9yZSBhYm91dCBpbXBvcnRpbmcgYW5kIHdyYW5nbGluZyBQREZzIHVzaW5nIHRoZSBgcGRmdG9vbHNgIHBhY2thZ2Ugc2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtcnVyYWwtYW5kLXVyYmFuLW9iZXNpdHkvKSBhbmQgdGhpcyBbY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1ydXJhbC1hbmQtdXJiYW4tb2Jlc2l0eS8pLiAKClRvIGxlYXJuIG1vcmUgYWJvdXQgd2hhdCB5b3UgY2FuIGRvIHdpdGggdGhlIGBtYWdpY2tgIHBhY2thZ2Ugc2VlIHRoaXMgW3ZpbmdldHRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFnaWNrL3ZpZ25ldHRlcy9pbnRyby5odG1sKS4gICAKClRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlICoqTWFubi1LZW5kYWxsIHRyZW5kIHRlc3QqKiBzZWUKW2hlcmVdKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5jb20vbWFubi1rZW5kYWxsLXRyZW5kLXRlc3QvKSBhbmQgW2hlcmVdKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTYvMDgvTWFubi1LZW5kYWxsLUFuYWx5c2lzLTEucGRmKS4gIAoKVG8gbGVhcm4gbW9yZSBhYm91dCBoeXBvdGhlc2lzIHRlc3RpbmcsIHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLXJ1cmFsLWFuZC11cmJhbi1vYmVzaXR5LykuICAgIAoKCjx1PioqUGFja2FnZXMgdXNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHk6KiogPC91PgoKUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YSAgCltwZGZ0b29sc10oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIGltcG9ydCBQREYgZG9jdW1lbnRzICAKW21hZ2lja10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ2ljay92aWduZXR0ZXMvaW50cm8uaHRtbCNLZXJuZWxfY29udm9sdXRpb24pICAgICAgfCBmb3IgaW1wb3J0aW5nIGltYWdlcyBhbmQgZXh0cmFjdGluZyB0ZXh0IGZyb20gaW1hZ2VzICAgCltrbml0cl0oaHR0cHM6Ly95aWh1aS5vcmcva25pdHIvKSB8ICBmb3Igc2hvd2luZyBpbWFnZXMgaW4gcmVwb3J0cyAgICAKW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBmaWx0ZXIsIHN1YnNldCwgam9pbiwgYWRkIHJvd3MgdG8sIGFuZCBtb2RpZnkgdGhlIGRhdGEgICAKW3N0cmluZ3JdKGh0dHBzOi8vc3RyaW5nci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gbWFuaXB1bGF0ZSBzdHJpbmdzICAKW21hZ3JpdHRyXShodHRwczovL21hZ3JpdHRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBwaXBlIHNlcXVlbnRpYWwgY29tbWFuZHMgClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY2hhbmdlIHRoZSBzaGFwZSBvciBmb3JtYXQgb2YgdGliYmxlcyB0byB3aWRlIGFuZCBsb25nLCB0byBkcm9wIHJvd3Mgd2l0aCBgTkFgIHZhbHVlcywgdG8gc2VwYXJhdGUgYSBjb2x1bW4gaW50byBhZGRpdGlvbmFsIGNvbHVtbnMsIGFuZCB0byBmaWxsIG91dCB2YWx1ZXMgYmFzZWQgb24gcHJldmlvdXMgdmFsdWVzICAgClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjcmVhdGUgdGliYmxlcyAgICAKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY3JlYXRlIHBsb3RzICAKW2RpcmVjdGxhYmVsc10oaHR0cDovL2RpcmVjdGxhYmVscy5yLWZvcmdlLnItcHJvamVjdC5vcmcvZG9jcy9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBhZGQgbGFiZWxzIGRpcmVjdGx5IHRvIGxpbmVzIGluIHBsb3RzICAKW2Nvd3Bsb3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3dwbG90L3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gYWRkIGltYWdlcyB0byBwbG90cyAKW2ZvcmNhdHNdKGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gcmVvcmRlciBmYWN0b3IgZm9yIHBsb3QKW2tlbmRhbGxdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9LZW5kYWxsL0tlbmRhbGwucGRmKSB8IHRvIGltcGxlbWVudCB0aGUgTWFubi1LZW5kYWxsIHRyZW5kIHRlc3QgaW4gUiAgIApbcGF0Y2h3b3JrXShodHRwczovL2dpdGh1Yi5jb20vdGhvbWFzcDg1L3BhdGNod29yaykgfCB0byBjb21iaW5lIHBsb3RzCgojIyMjIHsuZW1waGFzaXNfYmxvY2t9CgoqKldhcm5pbmcgU2lnbnMqKgoKRnJvbSBbU2FuZHkgSG9vayBQcm9taXNlXShodHRwczovL3d3dy5zYW5keWhvb2twcm9taXNlLm9yZy9ndW4tdmlvbGVuY2Uva25vdy10aGUtc2lnbnMtb2YtZ3VuLXZpb2xlbmNlLykuLi4KCkhlcmUgaXMgYSBsaXN0IG9mIHBvdGVudGlhbCB3YXJuaW5nIHNpZ25zIHRoYXQgY2FuIHNpZ25hbCBhbiBpbmRpdmlkdWFsIG1heSBiZSBpbiBjcmlzaXMgYW5kL29yIG5lZWQgaGVscDoKCisgU3VkZGVubHkgd2l0aGRyYXdpbmcgZnJvbSBwZW9wbGUgYW5kIGFjdGl2aXRpZXMKKyBDb25zaXN0ZW50IGJ1bGx5aW5nIG9yIGludGltaWRhdGluZyBvdGhlcnMsIG9yIGJlaW5nIGJ1bGxpZWQgYnkgb3RoZXJzCisgRXh0cmVtZSBtb29kIG9yIHBlcnNvbmFsaXR5IGNoYW5nZXMKKyBWaWN0aW0gb2YgY29uc3RhbnQgc29jaWFsIHJlamVjdGlvbgorIFRhbGtpbmcgYWJvdXQgcGxhbnMgb3IgYWN0aXZlbHkgbWFraW5nIHBsYW5zIHRvIGhhcm0gdGhlbXNlbHZlcyBvciBvdGhlcnMKKyBCcmluZ2luZyBhIHdlYXBvbiB0byBzY2hvb2wg4oCTIG9yIHRocmVhdGVuaW5nIG9yIHRhbGtpbmcgYWJvdXQgZG9pbmcgc28KKyBCcmFnZ2luZyBhYm91dCBvciB3YXJuaW5nIG90aGVycyBhYm91dCBhbiB1cGNvbWluZyBhY3Qgb2YgdmlvbGVuY2UKKyBSZWNydWl0aW5nIG90aGVycyB0byBqb2luIGluIGEgcGxhbm5lZCBhY3Qgb2YgdmlvbGVuY2UKKyBXYXJuaW5nIHN0dWRlbnRzIHRvIHN0YXkgYXdheSBmcm9tIHNjaG9vbCBvciBldmVudHMKKyBFeHByZXNzaW5nIGZhc2NpbmF0aW9uIHdpdGggZ3VucyBhbmQvb3Igc2Nob29sIHNob290aW5ncworIEV4cHJlc3NpbmcgaG9wZWxlc3NuZXNzIGFib3V0IHRoZSBmdXR1cmUKKyBFeHRyZW1lLCBwcm9sb25nZWQgc2FkbmVzcyBvciBkaXN0cmVzcworIEV4cHJlc3Npbmcgb3Igc2hvd2luZyBmZWVsaW5ncyBvZiBpc29sYXRpb24KKyBCcmFnZ2luZyBhYm91dCBhY2Nlc3MgdG8gZ3VucwoKKipOT1RFKioKClRoaXMgbGlzdCBpcyBub3QgYSBjb21wcmVoZW5zaXZlIGxpc3Qgb2Ygd2FybmluZyBzaWducyBub3IgZG9lcyBleGhpYml0aW5nIG9uZSBvZiB0aGVzZSBzaWducyBpbmRpY2F0ZSBpbW1pbmVudCB2aW9sZW5jZS4KCldoZW4gY29uY2VybmVkIGFib3V0IHNlZWluZyB0cm91YmxpbmcgYmVoYXZpb3JzLCB0ZWxsIGEgdHJ1c3RlZCBhZHVsdCBvciBjYWxsIDkxMSwgaWYgdGhlcmUgaXMgYW4gaW1tZWRpYXRlIHRocmVhdC4KCioqUmVzcG9uZCB0byBXYXJuaW5nIFNpZ25zKioKCkNhbGwgOTExIGlmIHlvdSBmZWVsIHRoZXJlIGlzIGFuIGltbWVkaWF0ZSB0aHJlYXQuIAoKQ2FsbCBbKzEtODQ0LTUtU0FZTk9XXSh0ZWw6MTg0NDU3Mjk2NjkpIGlmIHlvdSB3b3VsZCB0byBzdWJtaXQgYW4gYW5vbnltb3VzIHNhZmV0eSBjb25jZXJuLgoKCklmIHlvdSBvciB5b3VyIGNoaWxkIG9yIHN0dWRlbnQgZXhwZXJpZW5jZWQgYSBzaG9vdGluZyBwbGVhc2Ugc2VlIHRoaXMgW3dlYnNpdGVdKGh0dHBzOi8va2lkc2hlYWx0aC5vcmcvZW4vcGFyZW50cy9wdHNkLmh0bWwpIGFuZCB0aGlzIFt3ZWJzaXRlXShodHRwczovL3d3dy52ZXJ5d2VsbG1pbmQuY29tL3Nob290aW5nLXB0c2QtZnJvbS1hLXNob290aW5nLTI3OTcyMDApIGZvciBndWlkYW5jZSBhYm91dCBkZWFsaW5nIHdpdGggdGhlIHRyYXVtYS4KCgojIyMjCgojIyMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCgojIyMgQWNrbm93bGVkZ2VtZW50cwoKV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbRWxpemFiZXRoIFN0dWFydF0oaHR0cHM6Ly93d3cuamhzcGguZWR1L2ZhY3VsdHkvZGlyZWN0b3J5L3Byb2ZpbGUvMTc5Mi9lbGl6YWJldGgtYS1zdHVhcnQpIGZvciBhc3Npc3RpbmcgaW4gZnJhbWluZyB0aGUgbWFqb3IgZGlyZWN0aW9uIG9mIHRoZSBjYXNlIHN0dWR5LgoKV2Ugd291bGQgYWxzbyBsaWtlIHRvIGFja25vd2xlZGdlIHRoZSBbQmxvb21iZXJnIEFtZXJpY2FuIEhlYWx0aCBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvKSBmb3IgZnVuZGluZyB0aGlzIHdvcmsuIAoK